GameSentenceMiner 2.10.13__py3-none-any.whl → 2.10.14__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/obs.py +18 -4
- GameSentenceMiner/ocr/owocr_area_selector.py +20 -11
- GameSentenceMiner/ocr/owocr_helper.py +11 -5
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/RECORD +9 -9
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/top_level.txt +0 -0
GameSentenceMiner/obs.py
CHANGED
@@ -135,7 +135,7 @@ def get_obs_websocket_config_values():
|
|
135
135
|
full_config.save()
|
136
136
|
reload_config()
|
137
137
|
|
138
|
-
async def connect_to_obs(
|
138
|
+
async def connect_to_obs(retry=5):
|
139
139
|
global client, obs_connection_manager, event_client, connecting
|
140
140
|
if not get_config().obs.enabled:
|
141
141
|
return
|
@@ -166,11 +166,18 @@ async def connect_to_obs(retry_count=0):
|
|
166
166
|
update_current_game()
|
167
167
|
break # Exit the loop once connected
|
168
168
|
except Exception as e:
|
169
|
+
if retry <= 0:
|
170
|
+
gsm_status.obs_connected = False
|
171
|
+
logger.error(f"Failed to connect to OBS WebSocket: {e}")
|
172
|
+
client = None
|
173
|
+
event_client = None
|
174
|
+
connecting = False
|
175
|
+
break
|
169
176
|
await asyncio.sleep(1)
|
170
|
-
|
177
|
+
retry -= 1
|
171
178
|
connecting = False
|
172
179
|
|
173
|
-
def connect_to_obs_sync(
|
180
|
+
def connect_to_obs_sync(retry=2):
|
174
181
|
global client, obs_connection_manager, event_client
|
175
182
|
if not get_config().obs.enabled or client:
|
176
183
|
return
|
@@ -198,8 +205,15 @@ def connect_to_obs_sync(retry_count=0):
|
|
198
205
|
update_current_game()
|
199
206
|
break # Exit the loop once connected
|
200
207
|
except Exception as e:
|
208
|
+
if retry <= 0:
|
209
|
+
gsm_status.obs_connected = False
|
210
|
+
logger.error(f"Failed to connect to OBS WebSocket: {e}")
|
211
|
+
client = None
|
212
|
+
event_client = None
|
213
|
+
connecting = False
|
214
|
+
break
|
201
215
|
time.sleep(1)
|
202
|
-
|
216
|
+
retry -= 1
|
203
217
|
|
204
218
|
|
205
219
|
def disconnect_from_obs():
|
@@ -34,7 +34,7 @@ COORD_SYSTEM_PERCENTAGE = "percentage"
|
|
34
34
|
|
35
35
|
|
36
36
|
class ScreenSelector:
|
37
|
-
def __init__(self, result, window_name):
|
37
|
+
def __init__(self, result, window_name, use_window_as_config):
|
38
38
|
if not selector_available or not gw:
|
39
39
|
raise RuntimeError("tkinter or pygetwindow is not available.")
|
40
40
|
if not window_name:
|
@@ -60,6 +60,8 @@ class ScreenSelector:
|
|
60
60
|
# ---
|
61
61
|
|
62
62
|
self.root = None
|
63
|
+
self.scene = ''
|
64
|
+
self.use_window_as_config = use_window_as_config
|
63
65
|
self.result = result
|
64
66
|
self.rectangles = [] # Internal storage is ALWAYS absolute pixels for drawing
|
65
67
|
self.drawn_rect_ids = []
|
@@ -94,11 +96,14 @@ class ScreenSelector:
|
|
94
96
|
ocr_config_dir = app_dir / "ocr_config"
|
95
97
|
ocr_config_dir.mkdir(parents=True, exist_ok=True)
|
96
98
|
try:
|
97
|
-
|
99
|
+
if self.use_window_as_config:
|
100
|
+
self.scene = sanitize_filename(self.window_name)
|
101
|
+
else:
|
102
|
+
self.scene = sanitize_filename(obs.get_current_scene() or "")
|
98
103
|
except Exception as e:
|
99
104
|
print(f"Error getting OBS scene: {e}. Using default config name.")
|
100
|
-
scene = "
|
101
|
-
return ocr_config_dir / f"{scene}.json"
|
105
|
+
self.scene = ""
|
106
|
+
return ocr_config_dir / f"{self.scene}.json"
|
102
107
|
|
103
108
|
def load_existing_rectangles(self):
|
104
109
|
"""Loads rectangles from config, converting from percentage to absolute pixels for use."""
|
@@ -170,7 +175,7 @@ class ScreenSelector:
|
|
170
175
|
})
|
171
176
|
|
172
177
|
save_data = {
|
173
|
-
"scene":
|
178
|
+
"scene": self.scene or "",
|
174
179
|
"window": self.window_name,
|
175
180
|
"coordinate_system": COORD_SYSTEM_PERCENTAGE, # Always save as percentage
|
176
181
|
"window_geometry": win_geom, # Save the geometry used for conversion
|
@@ -397,9 +402,9 @@ class ScreenSelector:
|
|
397
402
|
self.root = None
|
398
403
|
|
399
404
|
|
400
|
-
def run_screen_selector(result_dict, window_name):
|
405
|
+
def run_screen_selector(result_dict, window_name, use_window_as_config):
|
401
406
|
try:
|
402
|
-
selector = ScreenSelector(result_dict, window_name)
|
407
|
+
selector = ScreenSelector(result_dict, window_name, use_window_as_config)
|
403
408
|
selector.start()
|
404
409
|
except Exception as e:
|
405
410
|
print(f"Error in selector process: {e}", file=sys.stderr)
|
@@ -408,7 +413,7 @@ def run_screen_selector(result_dict, window_name):
|
|
408
413
|
result_dict['error'] = str(e)
|
409
414
|
|
410
415
|
|
411
|
-
def get_screen_selection(window_name):
|
416
|
+
def get_screen_selection(window_name, use_window_as_config=False):
|
412
417
|
if not selector_available or not gw: return None
|
413
418
|
if not window_name:
|
414
419
|
print("Error: A target window name must be provided.", file=sys.stderr)
|
@@ -416,7 +421,7 @@ def get_screen_selection(window_name):
|
|
416
421
|
|
417
422
|
with Manager() as manager:
|
418
423
|
result_data = manager.dict()
|
419
|
-
process = Process(target=run_screen_selector, args=(result_data, window_name))
|
424
|
+
process = Process(target=run_screen_selector, args=(result_data, window_name, use_window_as_config))
|
420
425
|
print(f"Starting ScreenSelector process...")
|
421
426
|
process.start()
|
422
427
|
process.join()
|
@@ -434,11 +439,15 @@ def get_screen_selection(window_name):
|
|
434
439
|
|
435
440
|
if __name__ == "__main__":
|
436
441
|
set_dpi_awareness()
|
437
|
-
target_window_title = "
|
442
|
+
target_window_title = "YouTube - JP"
|
443
|
+
use_window_as_config = False
|
438
444
|
if len(sys.argv) > 1:
|
439
445
|
target_window_title = sys.argv[1]
|
446
|
+
if len(sys.argv) > 2:
|
447
|
+
use_window_as_config = True
|
448
|
+
target_window_title = sys.argv[1]
|
440
449
|
|
441
|
-
selection_result = get_screen_selection(target_window_title)
|
450
|
+
selection_result = get_screen_selection(target_window_title, use_window_as_config)
|
442
451
|
|
443
452
|
if selection_result is None:
|
444
453
|
print("\n--- Screen selection failed. ---")
|
@@ -47,13 +47,16 @@ console_handler.setFormatter(formatter)
|
|
47
47
|
logger.addHandler(console_handler)
|
48
48
|
|
49
49
|
|
50
|
-
def get_ocr_config(window=None) -> OCRConfig:
|
50
|
+
def get_ocr_config(window=None, use_window_for_config=False) -> OCRConfig:
|
51
51
|
"""Loads and updates screen capture areas from the corresponding JSON file."""
|
52
52
|
app_dir = Path.home() / "AppData" / "Roaming" / "GameSentenceMiner"
|
53
53
|
ocr_config_dir = app_dir / "ocr_config"
|
54
54
|
os.makedirs(ocr_config_dir, exist_ok=True)
|
55
|
-
obs.connect_to_obs_sync()
|
56
|
-
|
55
|
+
obs.connect_to_obs_sync(retry=0)
|
56
|
+
if use_window_for_config and window:
|
57
|
+
scene = sanitize_filename(window)
|
58
|
+
else:
|
59
|
+
scene = sanitize_filename(obs.get_current_scene())
|
57
60
|
config_path = ocr_config_dir / f"{scene}.json"
|
58
61
|
if not config_path.exists():
|
59
62
|
ocr_config = OCRConfig(scene=scene, window=window, rectangles=[], coordinate_system="percentage")
|
@@ -401,7 +404,7 @@ def set_force_stable_hotkey():
|
|
401
404
|
|
402
405
|
if __name__ == "__main__":
|
403
406
|
try:
|
404
|
-
global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window, optimize_second_scan
|
407
|
+
global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window, optimize_second_scan, use_window_for_config
|
405
408
|
import sys
|
406
409
|
|
407
410
|
import argparse
|
@@ -423,6 +426,8 @@ if __name__ == "__main__":
|
|
423
426
|
help="Hotkey for area selection OCR (default: ctrl+shift+o)")
|
424
427
|
parser.add_argument("--optimize_second_scan", action="store_true",
|
425
428
|
help="Optimize second scan by cropping based on first scan results")
|
429
|
+
parser.add_argument("--use_window_for_config", action="store_true",
|
430
|
+
help="Use the specified window for loading OCR configuration")
|
426
431
|
|
427
432
|
args = parser.parse_args()
|
428
433
|
|
@@ -440,11 +445,12 @@ if __name__ == "__main__":
|
|
440
445
|
"alt", "<alt>") if args.manual_ocr_hotkey else None
|
441
446
|
clipboard_output = args.clipboard_output
|
442
447
|
optimize_second_scan = args.optimize_second_scan
|
448
|
+
use_window_for_config = args.use_window_for_config
|
443
449
|
|
444
450
|
window = None
|
445
451
|
logger.info(f"Received arguments: {vars(args)}")
|
446
452
|
# set_force_stable_hotkey()
|
447
|
-
ocr_config: OCRConfig = get_ocr_config(window=window_name)
|
453
|
+
ocr_config: OCRConfig = get_ocr_config(window=window_name, use_window_for_config=use_window_for_config)
|
448
454
|
if ocr_config:
|
449
455
|
if ocr_config.window:
|
450
456
|
start_time = time.time()
|
@@ -3,7 +3,7 @@ GameSentenceMiner/anki.py,sha256=kWw3PV_Jj5-lHcttCB3lRXejHlaAbiJ2Ag_NAGX-RI8,166
|
|
3
3
|
GameSentenceMiner/config_gui.py,sha256=Xa_a-sdQzht3kzR-Z9gkLy4qnaPyP1bdVadYTHp5lUQ,91018
|
4
4
|
GameSentenceMiner/gametext.py,sha256=6VkjmBeiuZfPk8T6PHFdIAElBH2Y_oLVYvmcafqN7RM,6747
|
5
5
|
GameSentenceMiner/gsm.py,sha256=p4DVa_Jx1EOsgUxAAdC7st7VXLKWnP2BLDGT78ToO8w,24864
|
6
|
-
GameSentenceMiner/obs.py,sha256=
|
6
|
+
GameSentenceMiner/obs.py,sha256=o_I6213VZvXqYkZDdUBgUg2KWi9SbnNZZjjUnKnQkK4,15190
|
7
7
|
GameSentenceMiner/vad.py,sha256=G0NkaWFJaIfKQAV7LOFxyKoih7pPNYHDuy4SzeFVCkI,16389
|
8
8
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
GameSentenceMiner/ai/ai_prompting.py,sha256=0jBAnngNwmc3dqJiVWe_QRy4Syr-muV-ML2rq0FiUtU,10215
|
@@ -18,8 +18,8 @@ GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_
|
|
18
18
|
GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=jtTzAWtMAx8GuA1XIJ_BmyNn3aYaO3u_c5Q7m5D4gS8,4056
|
20
20
|
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
21
|
-
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=
|
22
|
-
GameSentenceMiner/ocr/owocr_helper.py,sha256=
|
21
|
+
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=lHMVZuEE_-_wICfDr6jDJNSJIyZd2PnF7dIajknaHCU,20255
|
22
|
+
GameSentenceMiner/ocr/owocr_helper.py,sha256=Iidu2T6z-eewFC40t3jUlLukankVsQB_HUEhr1L7HCU,22097
|
23
23
|
GameSentenceMiner/ocr/ss_picker.py,sha256=0IhxUdaKruFpZyBL-8SpxWg7bPrlGpy3lhTcMMZ5rwo,5224
|
24
24
|
GameSentenceMiner/owocr/owocr/__init__.py,sha256=87hfN5u_PbL_onLfMACbc0F5j4KyIK9lKnRCj6oZgR0,49
|
25
25
|
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
@@ -62,9 +62,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
62
62
|
GameSentenceMiner/web/templates/index.html,sha256=n0J-dV8eksj8JXUuaCTIh0fIxIjfgm2EvxGBdQ6gWoM,214113
|
63
63
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
64
64
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
65
|
-
gamesentenceminer-2.10.
|
66
|
-
gamesentenceminer-2.10.
|
67
|
-
gamesentenceminer-2.10.
|
68
|
-
gamesentenceminer-2.10.
|
69
|
-
gamesentenceminer-2.10.
|
70
|
-
gamesentenceminer-2.10.
|
65
|
+
gamesentenceminer-2.10.14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
66
|
+
gamesentenceminer-2.10.14.dist-info/METADATA,sha256=vnV_Sx7Xcs1DLFjkW4iKpwPNPf_ZFt83yVj7FSYtxAU,7355
|
67
|
+
gamesentenceminer-2.10.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
68
|
+
gamesentenceminer-2.10.14.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
69
|
+
gamesentenceminer-2.10.14.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
70
|
+
gamesentenceminer-2.10.14.dist-info/RECORD,,
|
File without changes
|
{gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/entry_points.txt
RENAMED
File without changes
|
{gamesentenceminer-2.10.13.dist-info → gamesentenceminer-2.10.14.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|