GameSentenceMiner 2.5.10__py3-none-any.whl → 2.5.12__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/anki.py +7 -7
- GameSentenceMiner/config_gui.py +0 -6
- GameSentenceMiner/configuration.py +0 -1
- GameSentenceMiner/gsm.py +87 -92
- GameSentenceMiner/obs.py +5 -21
- GameSentenceMiner/util.py +29 -35
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/METADATA +2 -2
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/RECORD +12 -12
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.5.10.dist-info → gamesentenceminer-2.5.12.dist-info}/top_level.txt +0 -0
GameSentenceMiner/anki.py
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
+
import time
|
2
|
+
|
1
3
|
import base64
|
2
4
|
import subprocess
|
3
5
|
import threading
|
4
|
-
import time
|
5
6
|
import urllib.request
|
6
7
|
from datetime import datetime, timedelta
|
8
|
+
from requests import post
|
7
9
|
|
8
|
-
import
|
9
|
-
|
10
|
-
from GameSentenceMiner import obs, util, notification, ffmpeg, gametext
|
11
|
-
|
10
|
+
from GameSentenceMiner import obs, util, notification, ffmpeg
|
12
11
|
from GameSentenceMiner.configuration import *
|
13
12
|
from GameSentenceMiner.configuration import get_config
|
14
13
|
from GameSentenceMiner.gametext import get_text_event
|
15
14
|
from GameSentenceMiner.model import AnkiCard
|
16
|
-
from GameSentenceMiner.utility_gui import
|
15
|
+
from GameSentenceMiner.utility_gui import get_utility_window
|
17
16
|
from GameSentenceMiner.obs import get_current_game
|
18
17
|
from GameSentenceMiner.util import remove_html_and_cloze_tags, combine_dialogue
|
19
18
|
|
19
|
+
|
20
20
|
audio_in_anki = None
|
21
21
|
screenshot_in_anki = None
|
22
22
|
prev_screenshot_in_anki = None
|
@@ -309,7 +309,7 @@ def monitor_anki():
|
|
309
309
|
|
310
310
|
# Fetch recent note IDs from Anki
|
311
311
|
def get_note_ids():
|
312
|
-
response =
|
312
|
+
response = post(get_config().anki.url, json={
|
313
313
|
"action": "findNotes",
|
314
314
|
"version": 6,
|
315
315
|
"params": {"query": "added:1"}
|
GameSentenceMiner/config_gui.py
CHANGED
@@ -835,12 +835,6 @@ class ConfigApp:
|
|
835
835
|
self.add_label_and_increment_row(obs_frame, "Password for the OBS WebSocket server.", row=self.current_row,
|
836
836
|
column=2)
|
837
837
|
|
838
|
-
ttk.Label(obs_frame, text="Start/Stop Buffer:").grid(row=self.current_row, column=0, sticky='W')
|
839
|
-
self.obs_start_buffer = tk.BooleanVar(value=self.settings.obs.start_buffer)
|
840
|
-
ttk.Checkbutton(obs_frame, variable=self.obs_start_buffer).grid(row=self.current_row, column=1, sticky='W')
|
841
|
-
self.add_label_and_increment_row(obs_frame, "Start and Stop the Buffer when Script runs.", row=self.current_row,
|
842
|
-
column=2)
|
843
|
-
|
844
838
|
ttk.Label(obs_frame, text="Get Game From Scene Name:").grid(row=self.current_row, column=0, sticky='W')
|
845
839
|
self.get_game_from_scene_name = tk.BooleanVar(value=self.settings.obs.get_game_from_scene)
|
846
840
|
ttk.Checkbutton(obs_frame, variable=self.get_game_from_scene_name).grid(row=self.current_row, column=1,
|
GameSentenceMiner/gsm.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
|
2
|
+
import os.path
|
1
3
|
import signal
|
2
|
-
import time
|
3
4
|
from subprocess import Popen
|
4
5
|
|
5
6
|
import keyboard
|
@@ -10,6 +11,8 @@ from pystray import Icon, Menu, MenuItem
|
|
10
11
|
from watchdog.events import FileSystemEventHandler
|
11
12
|
from watchdog.observers import Observer
|
12
13
|
|
14
|
+
import time
|
15
|
+
|
13
16
|
from GameSentenceMiner import anki
|
14
17
|
from GameSentenceMiner import config_gui
|
15
18
|
from GameSentenceMiner import configuration
|
@@ -28,11 +31,11 @@ from GameSentenceMiner.gametext import get_text_event, get_mined_line, GameLine
|
|
28
31
|
from GameSentenceMiner.obs import check_obs_folder_is_correct
|
29
32
|
from GameSentenceMiner.util import *
|
30
33
|
from GameSentenceMiner.utility_gui import init_utility_window, get_utility_window
|
31
|
-
from GameSentenceMiner.vad import silero_trim, whisper_helper, vosk_helper
|
32
34
|
|
33
35
|
if is_windows():
|
34
36
|
import win32api
|
35
37
|
|
38
|
+
silero_trim, whisper_helper, vosk_helper = None, None, None
|
36
39
|
procs_to_close = []
|
37
40
|
settings_window: config_gui.ConfigApp = None
|
38
41
|
obs_paused = False
|
@@ -41,51 +44,39 @@ menu: Menu
|
|
41
44
|
root = None
|
42
45
|
|
43
46
|
|
47
|
+
|
44
48
|
class VideoToAudioHandler(FileSystemEventHandler):
|
45
49
|
def on_created(self, event):
|
46
50
|
if event.is_directory or ("Replay" not in event.src_path and "GSM" not in event.src_path):
|
47
51
|
return
|
48
52
|
if event.src_path.endswith(".mkv") or event.src_path.endswith(".mp4"): # Adjust based on your OBS output format
|
49
53
|
logger.info(f"MKV {event.src_path} FOUND, RUNNING LOGIC")
|
50
|
-
|
54
|
+
wait_for_stable_file(event.src_path)
|
51
55
|
self.convert_to_audio(event.src_path)
|
52
56
|
|
53
|
-
@staticmethod
|
54
|
-
def wait_for_stable_file(file_path, timeout=10, check_interval=0.5):
|
55
|
-
elapsed_time = 0
|
56
|
-
last_size = -1
|
57
|
-
|
58
|
-
while elapsed_time < timeout:
|
59
|
-
try:
|
60
|
-
current_size = os.path.getsize(file_path)
|
61
|
-
if current_size == last_size:
|
62
|
-
return True
|
63
|
-
last_size = current_size
|
64
|
-
time.sleep(check_interval)
|
65
|
-
elapsed_time += check_interval
|
66
|
-
except Exception as e:
|
67
|
-
logger.warning(f"Error checking file size, will still try updating Anki Card!: {e}")
|
68
|
-
return False
|
69
|
-
logger.warning("File size did not stabilize within the timeout period. Continuing...")
|
70
|
-
return False
|
71
|
-
|
72
57
|
@staticmethod
|
73
58
|
def convert_to_audio(video_path):
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
59
|
+
try:
|
60
|
+
if get_utility_window().line_for_audio:
|
61
|
+
line: GameLine = get_utility_window().line_for_audio
|
62
|
+
get_utility_window().line_for_audio = None
|
63
|
+
if get_config().advanced.audio_player_path:
|
64
|
+
audio = VideoToAudioHandler.get_audio(line, line.next.time if line.next else None, video_path, temporary=True)
|
65
|
+
play_audio_in_external(audio)
|
66
|
+
os.remove(video_path)
|
67
|
+
elif get_config().advanced.video_player_path:
|
68
|
+
play_video_in_external(line, video_path)
|
69
|
+
return
|
70
|
+
if get_utility_window().line_for_screenshot:
|
71
|
+
line: GameLine = get_utility_window().line_for_screenshot
|
72
|
+
get_utility_window().line_for_screenshot = None
|
73
|
+
screenshot = ffmpeg.get_screenshot_for_line(video_path, line)
|
74
|
+
os.startfile(screenshot)
|
80
75
|
os.remove(video_path)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
line: GameLine = get_utility_window().line_for_screenshot
|
86
|
-
get_utility_window().line_for_screenshot = None
|
87
|
-
screenshot = ffmpeg.get_screenshot_for_line(video_path, line)
|
88
|
-
os.startfile(screenshot)
|
76
|
+
return
|
77
|
+
except Exception as e:
|
78
|
+
logger.error(f"Error Playing Audio/Video: {e}")
|
79
|
+
logger.debug(f"Error Playing Audio/Video: {e}", exc_info=True)
|
89
80
|
os.remove(video_path)
|
90
81
|
return
|
91
82
|
try:
|
@@ -158,10 +149,11 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
158
149
|
logger.error(f"Failed Processing and/or adding to Anki: Reason {e}")
|
159
150
|
logger.debug(f"Some error was hit catching to allow further work to be done: {e}", exc_info=True)
|
160
151
|
notification.send_error_no_anki_update()
|
161
|
-
|
162
|
-
os.
|
163
|
-
|
164
|
-
os.
|
152
|
+
finally:
|
153
|
+
if get_config().paths.remove_video and os.path.exists(video_path):
|
154
|
+
os.remove(video_path) # Optionally remove the video after conversion
|
155
|
+
if get_config().paths.remove_audio and os.path.exists(vad_trimmed_audio):
|
156
|
+
os.remove(vad_trimmed_audio) # Optionally remove the screenshot after conversion
|
165
157
|
|
166
158
|
|
167
159
|
@staticmethod
|
@@ -175,26 +167,10 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
175
167
|
f"{obs.get_current_game(sanitize=True)}.{get_config().audio.extension}"))
|
176
168
|
should_update_audio = True
|
177
169
|
if get_config().vad.do_vad_postprocessing:
|
178
|
-
|
179
|
-
case configuration.SILERO:
|
180
|
-
should_update_audio = silero_trim.process_audio_with_silero(trimmed_audio, vad_trimmed_audio)
|
181
|
-
case configuration.VOSK:
|
182
|
-
should_update_audio = vosk_helper.process_audio_with_vosk(trimmed_audio, vad_trimmed_audio)
|
183
|
-
case configuration.WHISPER:
|
184
|
-
should_update_audio = whisper_helper.process_audio_with_whisper(trimmed_audio,
|
185
|
-
vad_trimmed_audio)
|
170
|
+
should_update_audio = do_vad_processing(get_config().vad.selected_vad_model, trimmed_audio, vad_trimmed_audio)
|
186
171
|
if not should_update_audio:
|
187
|
-
|
188
|
-
|
189
|
-
pass
|
190
|
-
case configuration.SILERO:
|
191
|
-
should_update_audio = silero_trim.process_audio_with_silero(trimmed_audio,
|
192
|
-
vad_trimmed_audio)
|
193
|
-
case configuration.VOSK:
|
194
|
-
should_update_audio = vosk_helper.process_audio_with_vosk(trimmed_audio, vad_trimmed_audio)
|
195
|
-
case configuration.WHISPER:
|
196
|
-
should_update_audio = whisper_helper.process_audio_with_whisper(trimmed_audio,
|
197
|
-
vad_trimmed_audio)
|
172
|
+
should_update_audio = do_vad_processing(get_config().vad.selected_vad_model, trimmed_audio,
|
173
|
+
vad_trimmed_audio)
|
198
174
|
if not should_update_audio and get_config().vad.add_audio_on_no_results:
|
199
175
|
logger.info("No voice activity detected, using full audio.")
|
200
176
|
vad_trimmed_audio = trimmed_audio
|
@@ -206,6 +182,22 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
206
182
|
shutil.move(vad_trimmed_audio, final_audio_output)
|
207
183
|
return final_audio_output, should_update_audio, vad_trimmed_audio
|
208
184
|
|
185
|
+
|
186
|
+
def do_vad_processing(model, trimmed_audio, vad_trimmed_audio, second_pass=False):
|
187
|
+
match model:
|
188
|
+
case configuration.OFF:
|
189
|
+
pass
|
190
|
+
case configuration.SILERO:
|
191
|
+
from GameSentenceMiner.vad import silero_trim
|
192
|
+
return silero_trim.process_audio_with_silero(trimmed_audio, vad_trimmed_audio)
|
193
|
+
case configuration.VOSK:
|
194
|
+
from GameSentenceMiner.vad import vosk_helper
|
195
|
+
return vosk_helper.process_audio_with_vosk(trimmed_audio, vad_trimmed_audio)
|
196
|
+
case configuration.WHISPER:
|
197
|
+
from GameSentenceMiner.vad import whisper_helper
|
198
|
+
return whisper_helper.process_audio_with_whisper(trimmed_audio, vad_trimmed_audio)
|
199
|
+
|
200
|
+
|
209
201
|
def play_audio_in_external(filepath):
|
210
202
|
exe = get_config().advanced.audio_player_path
|
211
203
|
|
@@ -228,18 +220,19 @@ def play_video_in_external(line, filepath):
|
|
228
220
|
|
229
221
|
start, _, _ = get_video_timings(filepath, line)
|
230
222
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
command.append(
|
223
|
+
if start:
|
224
|
+
if "vlc" in get_config().advanced.video_player_path:
|
225
|
+
command.append("--start-time")
|
226
|
+
else:
|
227
|
+
command.append("--start")
|
228
|
+
command.append(convert_to_vlc_seconds(start))
|
229
|
+
command.append(os.path.normpath(filepath))
|
237
230
|
|
238
|
-
|
231
|
+
logger.info(" ".join(command))
|
239
232
|
|
240
233
|
try:
|
241
234
|
proc = subprocess.Popen(command)
|
242
|
-
print(f"Opened {filepath} in
|
235
|
+
print(f"Opened {filepath} in {get_config().advanced.video_player_path}.")
|
243
236
|
threading.Thread(target=remove_video_when_closed, args=(proc, filepath)).start()
|
244
237
|
except FileNotFoundError:
|
245
238
|
print("VLC not found. Make sure it's installed and in your PATH.")
|
@@ -279,7 +272,7 @@ def register_hotkeys():
|
|
279
272
|
def get_screenshot():
|
280
273
|
try:
|
281
274
|
image = obs.get_screenshot()
|
282
|
-
|
275
|
+
wait_for_stable_file(image, timeout=3)
|
283
276
|
if not image:
|
284
277
|
raise Exception("Failed to get Screenshot from OBS")
|
285
278
|
encoded_image = ffmpeg.process_image(image)
|
@@ -472,9 +465,8 @@ def cleanup():
|
|
472
465
|
util.keep_running = False
|
473
466
|
|
474
467
|
if get_config().obs.enabled:
|
475
|
-
|
476
|
-
|
477
|
-
obs.disconnect_from_obs()
|
468
|
+
obs.stop_replay_buffer()
|
469
|
+
obs.disconnect_from_obs()
|
478
470
|
if get_config().obs.close_obs:
|
479
471
|
close_obs()
|
480
472
|
|
@@ -514,9 +506,9 @@ def initialize(reloading=False):
|
|
514
506
|
if is_windows():
|
515
507
|
download_obs_if_needed()
|
516
508
|
download_ffmpeg_if_needed()
|
517
|
-
|
518
|
-
|
519
|
-
|
509
|
+
if get_config().obs.enabled:
|
510
|
+
if get_config().obs.open_obs:
|
511
|
+
obs_process = obs.start_obs()
|
520
512
|
# obs.connect_to_obs(start_replay=True)
|
521
513
|
# anki.start_monitoring_anki()
|
522
514
|
# gametext.start_text_monitor()
|
@@ -534,27 +526,29 @@ def initialize(reloading=False):
|
|
534
526
|
def initialize_async():
|
535
527
|
tasks = [gametext.start_text_monitor, connect_websocket, run_tray]
|
536
528
|
threads = []
|
537
|
-
|
538
|
-
if get_config().obs.open_obs:
|
539
|
-
tasks.append(obs.start_obs)
|
540
|
-
else:
|
541
|
-
tasks.append(obs.connect_to_obs)
|
542
|
-
tasks.append(anki.start_monitoring_anki)
|
543
|
-
if get_config().vad.do_vad_postprocessing:
|
544
|
-
if VOSK in (get_config().vad.backup_vad_model, get_config().vad.selected_vad_model):
|
545
|
-
tasks.append(vosk_helper.get_vosk_model)
|
546
|
-
if WHISPER in (get_config().vad.backup_vad_model, get_config().vad.selected_vad_model):
|
547
|
-
tasks.append(whisper_helper.initialize_whisper_model)
|
529
|
+
tasks.append(anki.start_monitoring_anki)
|
548
530
|
for task in tasks:
|
549
531
|
threads.append(util.run_new_thread(task))
|
550
532
|
return threads
|
551
533
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
534
|
+
|
535
|
+
def post_init():
|
536
|
+
def do_post_init():
|
537
|
+
global silero_trim, whisper_helper, vosk_helper
|
538
|
+
logger.info("Post-Initialization started.")
|
539
|
+
if get_config().obs.enabled:
|
540
|
+
obs.connect_to_obs()
|
541
|
+
check_obs_folder_is_correct()
|
542
|
+
from GameSentenceMiner.vad import vosk_helper
|
543
|
+
from GameSentenceMiner.vad import whisper_helper
|
544
|
+
if get_config().vad.is_vosk():
|
545
|
+
vosk_helper.get_vosk_model()
|
546
|
+
if get_config().vad.is_whisper():
|
547
|
+
whisper_helper.initialize_whisper_model()
|
548
|
+
if get_config().vad.is_silero():
|
549
|
+
from GameSentenceMiner.vad import silero_trim
|
550
|
+
|
551
|
+
util.run_new_thread(do_post_init)
|
558
552
|
|
559
553
|
|
560
554
|
def handle_websocket_message(message: Message):
|
@@ -574,7 +568,6 @@ def main(reloading=False):
|
|
574
568
|
init_utility_window(root)
|
575
569
|
initialize(reloading)
|
576
570
|
initialize_async()
|
577
|
-
check_obs_folder_is_correct()
|
578
571
|
observer = Observer()
|
579
572
|
observer.schedule(VideoToAudioHandler(), get_config().paths.folder_to_watch, recursive=False)
|
580
573
|
observer.start()
|
@@ -592,6 +585,7 @@ def main(reloading=False):
|
|
592
585
|
root.after(0, settings_window.show)
|
593
586
|
if get_config().general.open_multimine_on_startup:
|
594
587
|
root.after(0, get_utility_window().show)
|
588
|
+
root.after(0, post_init)
|
595
589
|
settings_window.add_save_hook(update_icon)
|
596
590
|
settings_window.on_exit = exit_program
|
597
591
|
root.mainloop()
|
@@ -606,4 +600,5 @@ def main(reloading=False):
|
|
606
600
|
|
607
601
|
|
608
602
|
if __name__ == "__main__":
|
603
|
+
logger.info("Starting GSM")
|
609
604
|
main()
|
GameSentenceMiner/obs.py
CHANGED
@@ -28,12 +28,9 @@ def start_obs():
|
|
28
28
|
return None
|
29
29
|
|
30
30
|
try:
|
31
|
-
|
32
|
-
|
33
|
-
return obs_pid
|
34
|
-
obs_process = subprocess.Popen([obs_path, '--disable-shutdown-check', '--portable'], cwd=os.path.dirname(obs_path))
|
31
|
+
obs_process = subprocess.Popen([obs_path, '--disable-shutdown-check', '--portable', '--startreplaybuffer'], cwd=os.path.dirname(obs_path))
|
32
|
+
|
35
33
|
logger.info("OBS launched")
|
36
|
-
connect_to_obs()
|
37
34
|
return obs_process.pid
|
38
35
|
except Exception as e:
|
39
36
|
logger.error(f"Error launching OBS: {e}")
|
@@ -48,15 +45,6 @@ def check_obs_folder_is_correct():
|
|
48
45
|
get_master_config().sync_shared_fields()
|
49
46
|
save_full_config(get_master_config())
|
50
47
|
|
51
|
-
def is_obs_running(obs_path):
|
52
|
-
obs_path = os.path.abspath(obs_path) # Normalize path
|
53
|
-
for process in psutil.process_iter(['exe']):
|
54
|
-
try:
|
55
|
-
if process.info['exe'] and os.path.abspath(process.info['exe']) == obs_path:
|
56
|
-
return process.pid
|
57
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
58
|
-
continue
|
59
|
-
return False
|
60
48
|
|
61
49
|
def get_obs_websocket_config_values():
|
62
50
|
config_path = os.path.join(get_app_directory(), 'obs-studio', 'config', 'obs-studio', 'plugin_config', 'obs-websocket', 'config.json')
|
@@ -92,10 +80,8 @@ def get_obs_websocket_config_values():
|
|
92
80
|
|
93
81
|
|
94
82
|
def on_connect(obs):
|
95
|
-
logger.info("
|
96
|
-
|
97
|
-
if get_config().obs.start_buffer:
|
98
|
-
start_replay_buffer()
|
83
|
+
logger.info("Reconnected to OBS WebSocket.")
|
84
|
+
start_replay_buffer()
|
99
85
|
|
100
86
|
|
101
87
|
def on_disconnect(obs):
|
@@ -111,9 +97,6 @@ def connect_to_obs():
|
|
111
97
|
password=get_config().obs.password, authreconnect=1, on_connect=on_connect,
|
112
98
|
on_disconnect=on_disconnect)
|
113
99
|
client.connect()
|
114
|
-
|
115
|
-
if get_config().obs.start_buffer:
|
116
|
-
start_replay_buffer()
|
117
100
|
update_current_game()
|
118
101
|
|
119
102
|
|
@@ -135,6 +118,7 @@ def do_obs_call(request, from_dict = None, retry=10):
|
|
135
118
|
return from_dict(response.datain)
|
136
119
|
return None
|
137
120
|
except Exception as e:
|
121
|
+
logger.error(e)
|
138
122
|
if "socket is already closed" in str(e) or "object has no attribute" in str(e):
|
139
123
|
if retry > 0:
|
140
124
|
time.sleep(1)
|
GameSentenceMiner/util.py
CHANGED
@@ -6,6 +6,7 @@ import string
|
|
6
6
|
import subprocess
|
7
7
|
import sys
|
8
8
|
import threading
|
9
|
+
import time
|
9
10
|
from datetime import datetime
|
10
11
|
from sys import platform
|
11
12
|
|
@@ -178,38 +179,31 @@ def combine_dialogue(dialogue_lines, new_lines=None):
|
|
178
179
|
|
179
180
|
return new_lines
|
180
181
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
# if get_config().vad.is_vosk():
|
210
|
-
# if check_and_install("vosk"):
|
211
|
-
# from GameSentenceMiner.vad import vosk_helper
|
212
|
-
# else:
|
213
|
-
# logger.error("Vosk is enabled and vosk package could not be installed.")
|
214
|
-
#
|
215
|
-
# return silero_trim, whisper_helper, vosk_helper
|
182
|
+
def wait_for_stable_file(file_path, timeout=10, check_interval=0.1):
|
183
|
+
elapsed_time = 0
|
184
|
+
last_size = -1
|
185
|
+
|
186
|
+
while elapsed_time < timeout:
|
187
|
+
try:
|
188
|
+
current_size = os.path.getsize(file_path)
|
189
|
+
if current_size == last_size:
|
190
|
+
return True
|
191
|
+
last_size = current_size
|
192
|
+
time.sleep(check_interval)
|
193
|
+
elapsed_time += check_interval
|
194
|
+
except Exception as e:
|
195
|
+
logger.warning(f"Error checking file size, will still try updating Anki Card!: {e}")
|
196
|
+
return False
|
197
|
+
logger.warning("File size did not stabilize within the timeout period. Continuing...")
|
198
|
+
return False
|
199
|
+
|
200
|
+
|
201
|
+
def import_vad_models():
|
202
|
+
silero_trim, whisper_helper, vosk_helper = None, None, None
|
203
|
+
if get_config().vad.is_silero():
|
204
|
+
from GameSentenceMiner.vad import silero_trim
|
205
|
+
if get_config().vad.is_whisper():
|
206
|
+
from GameSentenceMiner.vad import whisper_helper
|
207
|
+
if get_config().vad.is_vosk():
|
208
|
+
from GameSentenceMiner.vad import vosk_helper
|
209
|
+
return silero_trim, whisper_helper, vosk_helper
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GameSentenceMiner
|
3
|
-
Version: 2.5.
|
3
|
+
Version: 2.5.12
|
4
4
|
Summary: A tool for mining sentences from games. Update: Multi-Line Mining! Fixed!
|
5
5
|
Author-email: Beangate <bpwhelan95@gmail.com>
|
6
6
|
License: MIT License
|
@@ -97,7 +97,7 @@ steps before making an issue:
|
|
97
97
|
|
98
98
|
- Try Restarting OBS
|
99
99
|
- Make sure your hook is the best you can find. (Preferably it gives you the text RIGHT when the voice line starts)
|
100
|
-
- Try Adjusting Offset Configuration in
|
100
|
+
- Try Adjusting Offset Configuration in the config to better match your situation. (i.e. if the hook is late, add a
|
101
101
|
negative beginning offset)
|
102
102
|
- Try using "Trim beginning" in `VAD` settings.
|
103
103
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=
|
4
|
-
GameSentenceMiner/configuration.py,sha256=
|
2
|
+
GameSentenceMiner/anki.py,sha256=kMl-VvBkT_VtEjfTjliIHLGZwrJhHzTT1lRQ6qCdtYw,13062
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=9w7qXuGwt2lMTo4xXwuZKZyaLCoXBvzIDxSMrJzsUi8,60787
|
4
|
+
GameSentenceMiner/configuration.py,sha256=u6Jm-Ox7PSZ1Cf5_AkV6hvQInayq7jXjLduf1eMK7Rc,20119
|
5
5
|
GameSentenceMiner/ffmpeg.py,sha256=fzOxrn-a4KqFdUY2oove164CTDOSsdPQtzqRW5f1P7c,12002
|
6
6
|
GameSentenceMiner/gametext.py,sha256=LORVdE2WEo1CDI8gonc7qxrhbS4KFKXFQVKjhlkpLbc,7368
|
7
|
-
GameSentenceMiner/gsm.py,sha256=
|
7
|
+
GameSentenceMiner/gsm.py,sha256=H6kG2HerHhY37jXWGoQCLWjtzOoxAU_tAJ4RY9pAWbc,23970
|
8
8
|
GameSentenceMiner/model.py,sha256=JdnkT4VoPOXmOpRgFdvERZ09c9wLN6tUJxdrKlGZcqo,5305
|
9
9
|
GameSentenceMiner/notification.py,sha256=FY39ChSRK0Y8TQ6lBGsLnpZUFPtFpSy2tweeXVoV7kc,2809
|
10
|
-
GameSentenceMiner/obs.py,sha256=
|
10
|
+
GameSentenceMiner/obs.py,sha256=MlxRToq5wALPI1XrD8rxEU-N8mWII91cNJWY7rUa5uI,7642
|
11
11
|
GameSentenceMiner/package.py,sha256=YlS6QRMuVlm6mdXx0rlXv9_3erTGS21jaP3PNNWfAH0,1250
|
12
|
-
GameSentenceMiner/util.py,sha256=
|
12
|
+
GameSentenceMiner/util.py,sha256=Awhy57vX4NgQzygqKaGQn2EJ75T0uiXlhmINFOWlQkU,6825
|
13
13
|
GameSentenceMiner/utility_gui.py,sha256=H4aOddlsrVR768RwbMzYScCziuOz1JeySUigNrPlaac,7692
|
14
14
|
GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
|
15
15
|
GameSentenceMiner/communication/send.py,sha256=oOJdCS6-LNX90amkRn5FL2xqx6THGm56zHR2ntVIFTE,229
|
@@ -21,9 +21,9 @@ GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
21
21
|
GameSentenceMiner/vad/silero_trim.py,sha256=-thDIZLuTLra3YBj7WR16Z6JeDgSpge2YuahprBvD8I,1585
|
22
22
|
GameSentenceMiner/vad/vosk_helper.py,sha256=BI_mg_qyrjNbuEJjXSUDoV0FWEtQtEOAPmrrNixnZ_8,5974
|
23
23
|
GameSentenceMiner/vad/whisper_helper.py,sha256=OF4J8TPPoKPJR1uFwrWAZ2Q7v0HJkVvNGmF8l1tACX0,3447
|
24
|
-
gamesentenceminer-2.5.
|
25
|
-
gamesentenceminer-2.5.
|
26
|
-
gamesentenceminer-2.5.
|
27
|
-
gamesentenceminer-2.5.
|
28
|
-
gamesentenceminer-2.5.
|
29
|
-
gamesentenceminer-2.5.
|
24
|
+
gamesentenceminer-2.5.12.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
25
|
+
gamesentenceminer-2.5.12.dist-info/METADATA,sha256=iibLRrqHFjwy-4U4_j1JhHB3USB-W8CR0AMpW_JneF0,5433
|
26
|
+
gamesentenceminer-2.5.12.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
27
|
+
gamesentenceminer-2.5.12.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
28
|
+
gamesentenceminer-2.5.12.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
29
|
+
gamesentenceminer-2.5.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|