GameSentenceMiner 2.12.9__py3-none-any.whl → 2.12.11__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/gsm.py +133 -80
- GameSentenceMiner/ocr/owocr_helper.py +2 -3
- GameSentenceMiner/owocr/owocr/run.py +1 -0
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/RECORD +9 -9
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.12.9.dist-info → gamesentenceminer-2.12.11.dist-info}/top_level.txt +0 -0
GameSentenceMiner/gsm.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import time
|
1
2
|
import asyncio
|
2
3
|
import subprocess
|
3
4
|
import sys
|
@@ -7,12 +8,6 @@ import warnings
|
|
7
8
|
|
8
9
|
os.environ.pop('TCL_LIBRARY', None)
|
9
10
|
|
10
|
-
from GameSentenceMiner.util.gsm_utils import wait_for_stable_file, make_unique_file_name, run_new_thread
|
11
|
-
from GameSentenceMiner.util.communication.send import send_restart_signal
|
12
|
-
from GameSentenceMiner.util.downloader.download_tools import download_obs_if_needed, download_ffmpeg_if_needed
|
13
|
-
from GameSentenceMiner.vad import vad_processor
|
14
|
-
from GameSentenceMiner.util.model import VADResult
|
15
|
-
import time
|
16
11
|
|
17
12
|
try:
|
18
13
|
import os.path
|
@@ -27,7 +22,11 @@ try:
|
|
27
22
|
from watchdog.observers import Observer
|
28
23
|
import psutil
|
29
24
|
|
30
|
-
|
25
|
+
from GameSentenceMiner.util.model import VADResult
|
26
|
+
from GameSentenceMiner.vad import vad_processor
|
27
|
+
from GameSentenceMiner.util.downloader.download_tools import download_obs_if_needed, download_ffmpeg_if_needed
|
28
|
+
from GameSentenceMiner.util.communication.send import send_restart_signal
|
29
|
+
from GameSentenceMiner.util.gsm_utils import wait_for_stable_file, make_unique_file_name, run_new_thread
|
31
30
|
from GameSentenceMiner import anki
|
32
31
|
from GameSentenceMiner import config_gui
|
33
32
|
from GameSentenceMiner.util import configuration, notification, ffmpeg
|
@@ -46,7 +45,8 @@ try:
|
|
46
45
|
from GameSentenceMiner.web.texthooking_page import run_text_hooker_page
|
47
46
|
except Exception as e:
|
48
47
|
from GameSentenceMiner.util.configuration import logger, is_linux, is_windows
|
49
|
-
logger.info(
|
48
|
+
logger.info(
|
49
|
+
"Something bad happened during import/initialization, closing in 5 seconds")
|
50
50
|
logger.exception(e)
|
51
51
|
time.sleep(5)
|
52
52
|
sys.exit(1)
|
@@ -67,11 +67,11 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
67
67
|
def __init__(self):
|
68
68
|
super().__init__()
|
69
69
|
|
70
|
-
|
71
70
|
def on_created(self, event):
|
72
71
|
if event.is_directory or ("Replay" not in event.src_path and "GSM" not in event.src_path):
|
73
72
|
return
|
74
|
-
|
73
|
+
# Adjust based on your OBS output format
|
74
|
+
if event.src_path.endswith(".mkv") or event.src_path.endswith(".mp4"):
|
75
75
|
logger.info(f"MKV {event.src_path} FOUND, RUNNING LOGIC")
|
76
76
|
wait_for_stable_file(event.src_path)
|
77
77
|
self.process_replay(event.src_path)
|
@@ -85,15 +85,19 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
85
85
|
mined_line = None
|
86
86
|
gsm_state.previous_replay = video_path
|
87
87
|
if gsm_state.line_for_audio or gsm_state.line_for_screenshot:
|
88
|
-
handle_texthooker_button(
|
88
|
+
handle_texthooker_button(
|
89
|
+
video_path, get_audio_from_video=VideoToAudioHandler.get_audio)
|
89
90
|
return
|
90
91
|
try:
|
91
92
|
if anki.card_queue and len(anki.card_queue) > 0:
|
92
|
-
last_note, anki_card_creation_time, selected_lines = anki.card_queue.pop(
|
93
|
+
last_note, anki_card_creation_time, selected_lines = anki.card_queue.pop(
|
94
|
+
0)
|
93
95
|
elif get_config().features.backfill_audio:
|
94
|
-
last_note = anki.get_cards_by_sentence(
|
96
|
+
last_note = anki.get_cards_by_sentence(
|
97
|
+
gametext.current_line_after_regex)
|
95
98
|
else:
|
96
|
-
logger.info(
|
99
|
+
logger.info(
|
100
|
+
"Replay buffer initiated externally. Skipping processing.")
|
97
101
|
skip_delete = True
|
98
102
|
return
|
99
103
|
|
@@ -102,7 +106,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
102
106
|
if get_config().anki.update_anki:
|
103
107
|
last_note = anki.get_last_anki_card()
|
104
108
|
if get_config().features.backfill_audio:
|
105
|
-
last_note = anki.get_cards_by_sentence(
|
109
|
+
last_note = anki.get_cards_by_sentence(
|
110
|
+
gametext.current_line_after_regex)
|
106
111
|
|
107
112
|
# Get Info of line mined
|
108
113
|
line_cutoff = None
|
@@ -124,7 +129,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
124
129
|
if get_config().obs.minimum_replay_size and not ffmpeg.is_video_big_enough(video_path,
|
125
130
|
get_config().obs.minimum_replay_size):
|
126
131
|
logger.debug("Checking if video is big enough")
|
127
|
-
notification.send_check_obs_notification(
|
132
|
+
notification.send_check_obs_notification(
|
133
|
+
reason="Video may be empty, check scene in OBS.")
|
128
134
|
logger.error(
|
129
135
|
f"Video was unusually small, potentially empty! Check OBS for Correct Scene Settings! Path: {video_path}")
|
130
136
|
return
|
@@ -132,7 +138,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
132
138
|
if last_note:
|
133
139
|
logger.debug(last_note.to_json())
|
134
140
|
note = anki.get_initial_card_info(last_note, selected_lines)
|
135
|
-
tango = last_note.get_field(
|
141
|
+
tango = last_note.get_field(
|
142
|
+
get_config().anki.word_field) if last_note else ''
|
136
143
|
|
137
144
|
if get_config().anki.sentence_audio_field and get_config().audio.enabled:
|
138
145
|
logger.debug("Attempting to get audio from video")
|
@@ -147,11 +154,14 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
147
154
|
vad_result = VADResult(True, 0, 0, '')
|
148
155
|
vad_trimmed_audio = ""
|
149
156
|
if not get_config().audio.enabled:
|
150
|
-
logger.info(
|
157
|
+
logger.info(
|
158
|
+
"Audio is disabled in config, skipping audio processing!")
|
151
159
|
elif not get_config().anki.sentence_audio_field:
|
152
|
-
logger.info(
|
160
|
+
logger.info(
|
161
|
+
"No SentenceAudio Field in config, skipping audio processing!")
|
153
162
|
|
154
|
-
ss_timing = ffmpeg.get_screenshot_time(video_path, mined_line, vad_result=vad_result, doing_multi_line=bool(
|
163
|
+
ss_timing = ffmpeg.get_screenshot_time(video_path, mined_line, vad_result=vad_result, doing_multi_line=bool(
|
164
|
+
selected_lines), anki_card_creation_time=anki_card_creation_time)
|
155
165
|
# prev_ss_timing = 0
|
156
166
|
# if get_config().anki.previous_image_field and get_config().vad.do_vad_postprocessing:
|
157
167
|
# prev_ss_timing = ffmpeg.get_screenshot_time(video_path, mined_line.prev,
|
@@ -164,19 +174,22 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
164
174
|
if get_config().anki.update_anki and last_note:
|
165
175
|
anki.update_anki_card(
|
166
176
|
last_note, note, audio_path=final_audio_output, video_path=video_path,
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
177
|
+
tango=tango,
|
178
|
+
should_update_audio=vad_result.success,
|
179
|
+
ss_time=ss_timing,
|
180
|
+
game_line=mined_line,
|
171
181
|
selected_lines=selected_lines
|
172
182
|
)
|
173
183
|
elif get_config().features.notify_on_update and vad_result.success:
|
174
|
-
notification.send_audio_generated_notification(
|
184
|
+
notification.send_audio_generated_notification(
|
185
|
+
vad_trimmed_audio)
|
175
186
|
except Exception as e:
|
176
187
|
if mined_line:
|
177
188
|
anki_results[mined_line.id] = AnkiUpdateResult.failure()
|
178
|
-
logger.error(
|
179
|
-
|
189
|
+
logger.error(
|
190
|
+
f"Failed Processing and/or adding to Anki: Reason {e}", exc_info=True)
|
191
|
+
logger.debug(
|
192
|
+
f"Some error was hit catching to allow further work to be done: {e}", exc_info=True)
|
180
193
|
notification.send_error_no_anki_update()
|
181
194
|
finally:
|
182
195
|
if not skip_delete:
|
@@ -189,7 +202,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
189
202
|
|
190
203
|
@staticmethod
|
191
204
|
def get_audio(game_line, next_line_time, video_path, anki_card_creation_time=None, temporary=False, timing_only=False, mined_line=None):
|
192
|
-
trimmed_audio = get_audio_and_trim(
|
205
|
+
trimmed_audio = get_audio_and_trim(
|
206
|
+
video_path, game_line, next_line_time, anki_card_creation_time)
|
193
207
|
if temporary:
|
194
208
|
return ffmpeg.convert_audio_to_wav_lossless(trimmed_audio)
|
195
209
|
vad_trimmed_audio = make_unique_file_name(
|
@@ -197,7 +211,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
197
211
|
final_audio_output = make_unique_file_name(os.path.join(get_config().paths.audio_destination,
|
198
212
|
f"{obs.get_current_game(sanitize=True)}.{get_config().audio.extension}"))
|
199
213
|
|
200
|
-
vad_result = vad_processor.trim_audio_with_vad(
|
214
|
+
vad_result = vad_processor.trim_audio_with_vad(
|
215
|
+
trimmed_audio, vad_trimmed_audio, game_line)
|
201
216
|
if timing_only:
|
202
217
|
return vad_result
|
203
218
|
if vad_result.output_audio:
|
@@ -215,17 +230,21 @@ def initial_checks():
|
|
215
230
|
subprocess.run(ffmpeg.ffmpeg_base_command_list)
|
216
231
|
logger.debug("FFMPEG is installed and accessible.")
|
217
232
|
except FileNotFoundError:
|
218
|
-
logger.error(
|
233
|
+
logger.error(
|
234
|
+
"FFmpeg not found, please install it and add it to your PATH.")
|
219
235
|
raise
|
220
236
|
|
221
237
|
|
222
238
|
def register_hotkeys():
|
223
239
|
if get_config().hotkeys.reset_line:
|
224
|
-
keyboard.add_hotkey(get_config().hotkeys.reset_line,
|
240
|
+
keyboard.add_hotkey(get_config().hotkeys.reset_line,
|
241
|
+
gametext.reset_line_hotkey_pressed)
|
225
242
|
if get_config().hotkeys.take_screenshot:
|
226
|
-
keyboard.add_hotkey(
|
243
|
+
keyboard.add_hotkey(
|
244
|
+
get_config().hotkeys.take_screenshot, get_screenshot)
|
227
245
|
if get_config().hotkeys.play_latest_audio:
|
228
|
-
keyboard.add_hotkey(
|
246
|
+
keyboard.add_hotkey(
|
247
|
+
get_config().hotkeys.play_latest_audio, play_most_recent_audio)
|
229
248
|
|
230
249
|
|
231
250
|
def get_screenshot():
|
@@ -273,7 +292,8 @@ def get_screenshot():
|
|
273
292
|
# return image
|
274
293
|
|
275
294
|
def create_image():
|
276
|
-
image_path = os.path.join(os.path.dirname(
|
295
|
+
image_path = os.path.join(os.path.dirname(
|
296
|
+
__file__), "assets", "pickaxe.png")
|
277
297
|
return Image.open(image_path)
|
278
298
|
|
279
299
|
|
@@ -288,7 +308,8 @@ def play_most_recent_audio():
|
|
288
308
|
gsm_state.line_for_audio = get_all_lines()[-1]
|
289
309
|
obs.save_replay_buffer()
|
290
310
|
else:
|
291
|
-
logger.error(
|
311
|
+
logger.error(
|
312
|
+
"Feature Disabled. No audio or video player path set in config!")
|
292
313
|
|
293
314
|
|
294
315
|
def open_log():
|
@@ -411,7 +432,8 @@ def close_obs():
|
|
411
432
|
obs.disconnect_from_obs()
|
412
433
|
if obs.obs_process_pid:
|
413
434
|
try:
|
414
|
-
subprocess.run(["taskkill", "/PID", str(obs.obs_process_pid),
|
435
|
+
subprocess.run(["taskkill", "/PID", str(obs.obs_process_pid),
|
436
|
+
"/F"], check=True, capture_output=True, text=True)
|
415
437
|
print(f"OBS (PID {obs.obs_process_pid}) has been terminated.")
|
416
438
|
if os.path.exists(obs.OBS_PID_FILE):
|
417
439
|
os.remove(obs.OBS_PID_FILE)
|
@@ -476,6 +498,7 @@ def handle_exit():
|
|
476
498
|
|
477
499
|
return _handle_exit
|
478
500
|
|
501
|
+
|
479
502
|
def initialize(reloading=False):
|
480
503
|
global obs_process
|
481
504
|
if not reloading:
|
@@ -483,7 +506,8 @@ def initialize(reloading=False):
|
|
483
506
|
download_obs_if_needed()
|
484
507
|
download_ffmpeg_if_needed()
|
485
508
|
if shutil.which("ffmpeg") is None:
|
486
|
-
os.environ["PATH"] += os.pathsep +
|
509
|
+
os.environ["PATH"] += os.pathsep + \
|
510
|
+
os.path.dirname(get_ffmpeg_path())
|
487
511
|
if get_config().obs.enabled:
|
488
512
|
if get_config().obs.open_obs:
|
489
513
|
obs_process = obs.start_obs()
|
@@ -501,6 +525,7 @@ def initialize(reloading=False):
|
|
501
525
|
# if WHISPER in (get_config().vad.backup_vad_model, get_config().vad.selected_vad_model):
|
502
526
|
# whisper_helper.initialize_whisper_model()
|
503
527
|
|
528
|
+
|
504
529
|
def initialize_async():
|
505
530
|
tasks = [connect_websocket, run_tray]
|
506
531
|
threads = []
|
@@ -509,6 +534,7 @@ def initialize_async():
|
|
509
534
|
threads.append(run_new_thread(task))
|
510
535
|
return threads
|
511
536
|
|
537
|
+
|
512
538
|
def handle_websocket_message(message: Message):
|
513
539
|
match FunctionName(message.function):
|
514
540
|
case FunctionName.QUIT:
|
@@ -531,7 +557,9 @@ def handle_websocket_message(message: Message):
|
|
531
557
|
case FunctionName.EXIT:
|
532
558
|
exit_program(None, None)
|
533
559
|
case _:
|
534
|
-
logger.debug(
|
560
|
+
logger.debug(
|
561
|
+
f"unknown message from electron websocket: {message.to_json()}")
|
562
|
+
|
535
563
|
|
536
564
|
def post_init2():
|
537
565
|
asyncio.run(gametext.start_text_monitor())
|
@@ -546,7 +574,7 @@ def async_loop():
|
|
546
574
|
logger.info("Post-Initialization started.")
|
547
575
|
vad_processor.init()
|
548
576
|
# if is_beangate:
|
549
|
-
|
577
|
+
# await run_test_code()
|
550
578
|
|
551
579
|
asyncio.run(loop())
|
552
580
|
|
@@ -555,13 +583,16 @@ async def register_scene_switcher_callback():
|
|
555
583
|
def scene_switcher_callback(scene):
|
556
584
|
logger.info(f"Scene changed to: {scene}")
|
557
585
|
gsm_state.current_game = obs.get_current_game(sanitize=True)
|
558
|
-
all_configured_scenes = [
|
586
|
+
all_configured_scenes = [
|
587
|
+
config.scenes for config in get_master_config().configs.values()]
|
559
588
|
print(all_configured_scenes)
|
560
|
-
matching_configs = [name.strip() for name, config in config_instance.configs.items(
|
589
|
+
matching_configs = [name.strip() for name, config in config_instance.configs.items(
|
590
|
+
) if scene.strip() in config.scenes]
|
561
591
|
switch_to = None
|
562
592
|
|
563
593
|
if len(matching_configs) > 1:
|
564
|
-
selected_scene = settings_window.show_scene_selection(
|
594
|
+
selected_scene = settings_window.show_scene_selection(
|
595
|
+
matched_configs=matching_configs)
|
565
596
|
if selected_scene:
|
566
597
|
switch_to = selected_scene
|
567
598
|
else:
|
@@ -579,7 +610,8 @@ async def register_scene_switcher_callback():
|
|
579
610
|
update_icon()
|
580
611
|
|
581
612
|
await obs.register_scene_change_callback(scene_switcher_callback)
|
582
|
-
|
613
|
+
|
614
|
+
|
583
615
|
async def run_test_code():
|
584
616
|
if get_config().wip.overlay_websocket_port and get_config().wip.overlay_websocket_send:
|
585
617
|
boxes = await gametext.find_box_for_sentence("ちぇっ少しなの?")
|
@@ -587,48 +619,66 @@ async def run_test_code():
|
|
587
619
|
await texthooking_page.send_word_coordinates_to_overlay(boxes)
|
588
620
|
await asyncio.sleep(2)
|
589
621
|
|
622
|
+
|
590
623
|
async def async_main(reloading=False):
|
591
|
-
global root, settings_window
|
592
|
-
initialize(reloading)
|
593
|
-
logger.info("Script started.")
|
594
|
-
root = ttk.Window(themename='darkly')
|
595
|
-
settings_window = config_gui.ConfigApp(root)
|
596
|
-
initialize_async()
|
597
|
-
observer = Observer()
|
598
|
-
observer.schedule(VideoToAudioHandler(), get_config().paths.folder_to_watch, recursive=False)
|
599
|
-
observer.start()
|
600
|
-
if not is_windows():
|
601
|
-
register_hotkeys()
|
602
|
-
|
603
|
-
run_new_thread(post_init2)
|
604
|
-
run_new_thread(run_text_hooker_page)
|
605
|
-
run_new_thread(async_loop)
|
606
|
-
|
607
|
-
# Register signal handlers for graceful shutdown
|
608
|
-
signal.signal(signal.SIGTERM, handle_exit()) # Handle `kill` commands
|
609
|
-
signal.signal(signal.SIGINT, handle_exit()) # Handle Ctrl+C
|
610
|
-
if is_windows():
|
611
|
-
win32api.SetConsoleCtrlHandler(handle_exit())
|
612
|
-
|
613
|
-
gsm_status.ready = True
|
614
|
-
gsm_status.status = "Ready"
|
615
624
|
try:
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
625
|
+
global root, settings_window
|
626
|
+
initialize(reloading)
|
627
|
+
logger.info("Script started.")
|
628
|
+
root = ttk.Window(themename='darkly')
|
629
|
+
settings_window = config_gui.ConfigApp(root)
|
630
|
+
initialize_async()
|
631
|
+
observer = Observer()
|
632
|
+
observer.schedule(VideoToAudioHandler(),
|
633
|
+
get_config().paths.folder_to_watch, recursive=False)
|
634
|
+
observer.start()
|
635
|
+
if is_windows():
|
636
|
+
register_hotkeys()
|
623
637
|
|
624
|
-
|
625
|
-
|
626
|
-
|
638
|
+
run_new_thread(post_init2)
|
639
|
+
run_new_thread(run_text_hooker_page)
|
640
|
+
run_new_thread(async_loop)
|
641
|
+
|
642
|
+
# Register signal handlers for graceful shutdown
|
643
|
+
signal.signal(signal.SIGTERM, handle_exit()) # Handle `kill` commands
|
644
|
+
signal.signal(signal.SIGINT, handle_exit()) # Handle Ctrl+C
|
645
|
+
if is_windows():
|
646
|
+
win32api.SetConsoleCtrlHandler(handle_exit())
|
647
|
+
|
648
|
+
gsm_status.ready = True
|
649
|
+
gsm_status.status = "Ready"
|
650
|
+
try:
|
651
|
+
if get_config().general.open_config_on_startup:
|
652
|
+
root.after(50, settings_window.show)
|
653
|
+
settings_window.add_save_hook(update_icon)
|
654
|
+
settings_window.on_exit = exit_program
|
655
|
+
root.mainloop()
|
656
|
+
except KeyboardInterrupt:
|
657
|
+
cleanup()
|
658
|
+
|
659
|
+
try:
|
660
|
+
observer.stop()
|
661
|
+
observer.join()
|
662
|
+
except Exception as e:
|
663
|
+
logger.error(f"Error stopping observer: {e}")
|
627
664
|
except Exception as e:
|
628
|
-
logger.error(f"
|
665
|
+
logger.error(f"An error occurred during initialization: {e}", exc_info=True)
|
666
|
+
notification.send_error_notification(
|
667
|
+
"An error occurred during initialization. Check the log for details.")
|
668
|
+
asyncio.sleep(5)
|
669
|
+
raise e
|
670
|
+
|
629
671
|
|
630
672
|
def main():
|
631
|
-
|
673
|
+
"""Main function to run the Game Sentence Miner."""
|
674
|
+
logger.info("Starting GSM")
|
675
|
+
try:
|
676
|
+
asyncio.run(async_main())
|
677
|
+
except Exception as e:
|
678
|
+
logger.exception(e, exc_info=True)
|
679
|
+
logger.info(
|
680
|
+
"An error occurred during initialization, closing in 5 seconds")
|
681
|
+
time.sleep(5)
|
632
682
|
|
633
683
|
|
634
684
|
if __name__ == "__main__":
|
@@ -636,4 +686,7 @@ if __name__ == "__main__":
|
|
636
686
|
try:
|
637
687
|
asyncio.run(async_main())
|
638
688
|
except Exception as e:
|
639
|
-
logger.exception(e)
|
689
|
+
logger.exception(e, exc_info=True)
|
690
|
+
logger.info(
|
691
|
+
"An error occurred during initialization, closing in 5 seconds")
|
692
|
+
time.sleep(5)
|
@@ -305,6 +305,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
305
305
|
|
306
306
|
line_start_time = time if time else datetime.now()
|
307
307
|
|
308
|
+
|
308
309
|
if manual or not get_ocr_two_pass_ocr():
|
309
310
|
if compare_ocr_results(last_sent_result, text, 80):
|
310
311
|
if text:
|
@@ -320,8 +321,6 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
320
321
|
last_oneocr_time = None
|
321
322
|
return
|
322
323
|
if not text or force_stable:
|
323
|
-
# or FUTURE ATTEMPT, I THINK THIS IS CLOSE?
|
324
|
-
# (orig_text and previous_text and len(orig_text) == len(previous_text_list) and len(orig_text[0] < len(previous_text_list)))):
|
325
324
|
force_stable = False
|
326
325
|
if previous_text and text_stable_start_time:
|
327
326
|
stable_time = text_stable_start_time
|
@@ -349,7 +348,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
349
348
|
# Make sure it's an actual new line before starting the timer
|
350
349
|
if text and compare_ocr_results(orig_text_string, previous_orig_text):
|
351
350
|
return
|
352
|
-
|
351
|
+
|
353
352
|
if not text_stable_start_time:
|
354
353
|
text_stable_start_time = line_start_time
|
355
354
|
previous_text = text
|
@@ -2,7 +2,7 @@ GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
2
2
|
GameSentenceMiner/anki.py,sha256=FUwcWO0-arzfQjejQmDKP7pNNakhboo8InQ4s_jv6AY,19099
|
3
3
|
GameSentenceMiner/config_gui.py,sha256=UCipZVAVupJeA8Kaa1tqTBsZpErNIIePJabqKh4SI7s,105693
|
4
4
|
GameSentenceMiner/gametext.py,sha256=TYlkgM5-J2o8-WCKypSUitmKq_UcjOGpsZBINiR-mWk,10875
|
5
|
-
GameSentenceMiner/gsm.py,sha256=
|
5
|
+
GameSentenceMiner/gsm.py,sha256=bNZmHcZt_sLt-WDnYtRZsv5NYRbw_59V79eOggg_Ym0,26662
|
6
6
|
GameSentenceMiner/obs.py,sha256=bMVWAPQ6QLf4celLiOsL9BUO8pTdMn9lpT9fQCNfm7Q,18718
|
7
7
|
GameSentenceMiner/vad.py,sha256=-Q1KtDJnT8zRFeEc4LLyAECf07YOUM15UDRrnWkuDgo,18817
|
8
8
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -19,14 +19,14 @@ GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
19
19
|
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=Ezj-0k6Wo-una91FvYhMp6KGkRhWYihXzLAoh_Wu2xY,5329
|
20
20
|
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
21
21
|
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=seTO8kUCTW445qAUo4c7mvLtiv1SWeElpSUpP9DPDOA,26331
|
22
|
-
GameSentenceMiner/ocr/owocr_helper.py,sha256=
|
22
|
+
GameSentenceMiner/ocr/owocr_helper.py,sha256=nyNCt6TtOFvcXddwaNXpkuYbCsfBG5Nvp6b8mU-6jlg,25236
|
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
|
26
26
|
GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
|
27
27
|
GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
|
28
28
|
GameSentenceMiner/owocr/owocr/ocr.py,sha256=jjm7TGIOaR-7JfoP_4B24uW7tLsxJL36s2kFndJy_SA,63025
|
29
|
-
GameSentenceMiner/owocr/owocr/run.py,sha256=
|
29
|
+
GameSentenceMiner/owocr/owocr/run.py,sha256=Qm4srtzqj6tZhgicMME4SyjP6NP_2IQRN-AOzVzE828,66011
|
30
30
|
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
31
31
|
GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
GameSentenceMiner/util/audio_offset_selector.py,sha256=8Stk3BP-XVIuzRv9nl9Eqd2D-1yD3JrgU-CamBywJmY,8542
|
@@ -64,9 +64,9 @@ GameSentenceMiner/web/templates/index.html,sha256=Gv3CJvNnhAzIVV_QxhNq4OD-pXDt1v
|
|
64
64
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
65
65
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
66
66
|
GameSentenceMiner/wip/get_overlay_coords.py,sha256=_re9zfyuFryZAUKbMQ1LAfQBDIRUmq_1kniisN7J7xE,19793
|
67
|
-
gamesentenceminer-2.12.
|
68
|
-
gamesentenceminer-2.12.
|
69
|
-
gamesentenceminer-2.12.
|
70
|
-
gamesentenceminer-2.12.
|
71
|
-
gamesentenceminer-2.12.
|
72
|
-
gamesentenceminer-2.12.
|
67
|
+
gamesentenceminer-2.12.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
68
|
+
gamesentenceminer-2.12.11.dist-info/METADATA,sha256=nGANkSYsrLfHVpnRMqewYouhR7UzFJMfuB5xGOy2v3E,7069
|
69
|
+
gamesentenceminer-2.12.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
70
|
+
gamesentenceminer-2.12.11.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
71
|
+
gamesentenceminer-2.12.11.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
72
|
+
gamesentenceminer-2.12.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|