GameSentenceMiner 2.0.0__py3-none-any.whl → 2.0.0.dev1__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/config_gui.py +1 -3
- GameSentenceMiner/configuration.py +46 -28
- GameSentenceMiner/ffmpeg.py +2 -2
- GameSentenceMiner/gsm.py +24 -35
- GameSentenceMiner/obs.py +1 -1
- GameSentenceMiner/vad/silero_trim.py +1 -1
- GameSentenceMiner/vad/vosk_helper.py +1 -1
- GameSentenceMiner/vad/whisper_helper.py +1 -1
- {GameSentenceMiner-2.0.0.dist-info → GameSentenceMiner-2.0.0.dev1.dist-info}/METADATA +1 -1
- GameSentenceMiner-2.0.0.dev1.dist-info/RECORD +20 -0
- GameSentenceMiner-2.0.0.dist-info/RECORD +0 -20
- {GameSentenceMiner-2.0.0.dist-info → GameSentenceMiner-2.0.0.dev1.dist-info}/WHEEL +0 -0
- {GameSentenceMiner-2.0.0.dist-info → GameSentenceMiner-2.0.0.dev1.dist-info}/entry_points.txt +0 -0
- {GameSentenceMiner-2.0.0.dist-info → GameSentenceMiner-2.0.0.dev1.dist-info}/top_level.txt +0 -0
GameSentenceMiner/config_gui.py
CHANGED
@@ -7,8 +7,6 @@ from . import configuration
|
|
7
7
|
from . import obs
|
8
8
|
from .configuration import *
|
9
9
|
|
10
|
-
TOML_CONFIG_FILE = '../../config.toml'
|
11
|
-
CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'config.json')
|
12
10
|
settings_saved = False
|
13
11
|
on_save = []
|
14
12
|
|
@@ -186,7 +184,7 @@ class ConfigApp:
|
|
186
184
|
self.master_config.set_config_for_profile(current_profile, config)
|
187
185
|
|
188
186
|
# Serialize the config instance to JSON
|
189
|
-
with open(
|
187
|
+
with open(get_config_path(), 'w') as file:
|
190
188
|
file.write(self.master_config.to_json(indent=4))
|
191
189
|
|
192
190
|
print("Settings saved successfully!")
|
@@ -216,7 +216,7 @@ class ProfileConfig:
|
|
216
216
|
|
217
217
|
self.anki.anki_custom_fields = config_data.get('anki_custom_fields', {})
|
218
218
|
|
219
|
-
with open(
|
219
|
+
with open(get_config_path(), 'w') as f:
|
220
220
|
f.write(self.to_json(indent=4))
|
221
221
|
print(
|
222
222
|
'config.json successfully generated from previous settings. config.toml will no longer be used.')
|
@@ -247,38 +247,33 @@ class Config:
|
|
247
247
|
def get_all_profile_names(self):
|
248
248
|
return list(self.configs.keys())
|
249
249
|
|
250
|
-
|
251
|
-
logger = logging.getLogger("GameSentenceMiner")
|
252
|
-
logger.setLevel(logging.DEBUG) # Set the base level to DEBUG so that all messages are captured
|
253
|
-
|
254
|
-
# Create console handler with level INFO
|
255
|
-
console_handler = logging.StreamHandler()
|
256
|
-
console_handler.setLevel(logging.INFO)
|
257
|
-
|
258
|
-
# Create rotating file handler with level DEBUG
|
259
|
-
file_handler = RotatingFileHandler("gamesentenceminer.log", maxBytes=10_000_000, backupCount=2, encoding='utf-8')
|
260
|
-
file_handler.setLevel(logging.DEBUG)
|
261
|
-
|
262
|
-
# Create a formatter
|
263
|
-
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
264
|
-
|
265
|
-
# Add formatter to handlers
|
266
|
-
console_handler.setFormatter(formatter)
|
267
|
-
file_handler.setFormatter(formatter)
|
268
|
-
|
269
|
-
# Add handlers to the logger
|
270
|
-
logger.addHandler(console_handler)
|
271
|
-
logger.addHandler(file_handler)
|
272
|
-
|
273
|
-
CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'get_config().json')
|
274
|
-
temp_directory = ''
|
275
|
-
|
276
250
|
def get_app_directory():
|
277
251
|
appdata_dir = os.getenv('APPDATA') # Get the AppData directory
|
278
252
|
config_dir = os.path.join(appdata_dir, 'GameSentenceMiner')
|
279
253
|
os.makedirs(config_dir, exist_ok=True) # Create the directory if it doesn't exist
|
280
254
|
return config_dir
|
281
255
|
|
256
|
+
def get_log_path():
|
257
|
+
return os.path.join(get_app_directory(), 'gamesentenceminer.log')
|
258
|
+
|
259
|
+
temp_directory = ''
|
260
|
+
|
261
|
+
def get_temporary_directory():
|
262
|
+
global temp_directory
|
263
|
+
if not temp_directory:
|
264
|
+
temp_directory = os.path.join(get_app_directory(), 'temp')
|
265
|
+
os.makedirs(temp_directory, exist_ok=True)
|
266
|
+
for filename in os.listdir(temp_directory):
|
267
|
+
file_path = os.path.join(temp_directory, filename)
|
268
|
+
try:
|
269
|
+
if os.path.isfile(file_path) or os.path.islink(file_path):
|
270
|
+
os.unlink(file_path)
|
271
|
+
elif os.path.isdir(file_path):
|
272
|
+
shutil.rmtree(file_path)
|
273
|
+
except Exception as e:
|
274
|
+
logger.error(f"Failed to delete {file_path}. Reason: {e}")
|
275
|
+
return temp_directory
|
276
|
+
|
282
277
|
def get_config_path():
|
283
278
|
return os.path.join(get_app_directory(), 'config.json')
|
284
279
|
|
@@ -354,6 +349,29 @@ def get_master_config():
|
|
354
349
|
def switch_profile_and_save(profile_name):
|
355
350
|
global config_instance
|
356
351
|
config_instance.current_profile = profile_name
|
357
|
-
with open(
|
352
|
+
with open(get_config_path(), 'w') as file:
|
358
353
|
json.dump(config_instance.to_dict(), file, indent=4)
|
359
354
|
return config_instance.get_config()
|
355
|
+
|
356
|
+
|
357
|
+
logger = logging.getLogger("GameSentenceMiner")
|
358
|
+
logger.setLevel(logging.DEBUG) # Set the base level to DEBUG so that all messages are captured
|
359
|
+
|
360
|
+
# Create console handler with level INFO
|
361
|
+
console_handler = logging.StreamHandler()
|
362
|
+
console_handler.setLevel(logging.INFO)
|
363
|
+
|
364
|
+
# Create rotating file handler with level DEBUG
|
365
|
+
file_handler = RotatingFileHandler(get_log_path(), maxBytes=10_000_000, backupCount=2, encoding='utf-8')
|
366
|
+
file_handler.setLevel(logging.DEBUG)
|
367
|
+
|
368
|
+
# Create a formatter
|
369
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
370
|
+
|
371
|
+
# Add formatter to handlers
|
372
|
+
console_handler.setFormatter(formatter)
|
373
|
+
file_handler.setFormatter(formatter)
|
374
|
+
|
375
|
+
# Add handlers to the logger
|
376
|
+
logger.addHandler(console_handler)
|
377
|
+
logger.addHandler(file_handler)
|
GameSentenceMiner/ffmpeg.py
CHANGED
@@ -128,7 +128,7 @@ def get_audio_and_trim(video_path, line_time, next_line_time):
|
|
128
128
|
codec_command = ["-c:a", f"{supported_formats[get_config().audio.extension]}"]
|
129
129
|
logger.info(f"Re-encoding {codec} to {get_config().audio.extension}")
|
130
130
|
|
131
|
-
untrimmed_audio = tempfile.NamedTemporaryFile(dir=configuration.
|
131
|
+
untrimmed_audio = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(),
|
132
132
|
suffix=f"_untrimmed.{get_config().audio.extension}").name
|
133
133
|
|
134
134
|
command = ffmpeg_base_command_list + [
|
@@ -161,7 +161,7 @@ def get_video_duration(file_path):
|
|
161
161
|
|
162
162
|
|
163
163
|
def trim_audio_based_on_last_line(untrimmed_audio, video_path, line_time, next_line):
|
164
|
-
trimmed_audio = tempfile.NamedTemporaryFile(dir=configuration.
|
164
|
+
trimmed_audio = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(),
|
165
165
|
suffix=f".{get_config().audio.extension}").name
|
166
166
|
file_mod_time = get_file_modification_time(video_path)
|
167
167
|
file_length = get_video_duration(video_path)
|
GameSentenceMiner/gsm.py
CHANGED
@@ -105,7 +105,7 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
105
105
|
def get_audio(line_time, next_line_time, video_path):
|
106
106
|
trimmed_audio = get_audio_and_trim(video_path, line_time, next_line_time)
|
107
107
|
vad_trimmed_audio = make_unique_file_name(
|
108
|
-
f"{os.path.abspath(configuration.
|
108
|
+
f"{os.path.abspath(configuration.get_temporary_directory())}/{obs.get_current_game(sanitize=True)}.{get_config().audio.extension}")
|
109
109
|
final_audio_output = make_unique_file_name(
|
110
110
|
f"{get_config().paths.audio_destination}{obs.get_current_game(sanitize=True)}.{get_config().audio.extension}")
|
111
111
|
should_update_audio = True
|
@@ -153,15 +153,6 @@ def initialize(reloading=False):
|
|
153
153
|
os.mkdir(get_config().paths.screenshot_destination)
|
154
154
|
if not os.path.exists(get_config().paths.audio_destination):
|
155
155
|
os.mkdir(get_config().paths.audio_destination)
|
156
|
-
if not os.path.exists("../temp_files"):
|
157
|
-
os.mkdir("../temp_files")
|
158
|
-
else:
|
159
|
-
for filename in os.scandir('../temp_files'):
|
160
|
-
file_path = os.path.join('../temp_files', filename.name)
|
161
|
-
if filename.is_file() or filename.is_symlink():
|
162
|
-
os.remove(file_path)
|
163
|
-
elif filename.is_dir():
|
164
|
-
shutil.rmtree(file_path)
|
165
156
|
if get_config().vad.do_vad_postprocessing:
|
166
157
|
if VOSK in (get_config().vad.backup_vad_model, get_config().vad.selected_vad_model):
|
167
158
|
vosk_helper.get_vosk_model()
|
@@ -349,36 +340,34 @@ def main(reloading=False, do_config_input=True):
|
|
349
340
|
global settings_window
|
350
341
|
logger.info("Script started.")
|
351
342
|
initialize(reloading)
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
observer.schedule(event_handler, get_config().paths.folder_to_watch, recursive=False)
|
357
|
-
observer.start()
|
343
|
+
event_handler = VideoToAudioHandler()
|
344
|
+
observer = Observer()
|
345
|
+
observer.schedule(event_handler, get_config().paths.folder_to_watch, recursive=False)
|
346
|
+
observer.start()
|
358
347
|
|
359
|
-
|
360
|
-
|
361
|
-
|
348
|
+
logger.info("Script Initialized. Happy Mining!")
|
349
|
+
if not is_linux():
|
350
|
+
register_hotkeys()
|
362
351
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
352
|
+
# Register signal handlers for graceful shutdown
|
353
|
+
signal.signal(signal.SIGTERM, handle_exit()) # Handle `kill` commands
|
354
|
+
signal.signal(signal.SIGINT, handle_exit()) # Handle Ctrl+C
|
355
|
+
win32api.SetConsoleCtrlHandler(handle_exit())
|
367
356
|
|
368
|
-
|
357
|
+
util.run_new_thread(run_tray)
|
369
358
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
359
|
+
try:
|
360
|
+
settings_window = config_gui.ConfigApp()
|
361
|
+
settings_window.add_save_hook(update_icon)
|
362
|
+
settings_window.window.mainloop()
|
363
|
+
except KeyboardInterrupt:
|
364
|
+
cleanup()
|
376
365
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
366
|
+
try:
|
367
|
+
observer.stop()
|
368
|
+
observer.join()
|
369
|
+
except Exception as e:
|
370
|
+
logger.error(f"Error stopping observer: {e}")
|
382
371
|
|
383
372
|
|
384
373
|
if __name__ == "__main__":
|
GameSentenceMiner/obs.py
CHANGED
@@ -101,7 +101,7 @@ def get_source_from_scene(scene_name):
|
|
101
101
|
|
102
102
|
def get_screenshot():
|
103
103
|
try:
|
104
|
-
screenshot = util.make_unique_file_name(os.path.abspath(configuration.
|
104
|
+
screenshot = util.make_unique_file_name(os.path.abspath(configuration.get_temporary_directory()) + '/screenshot.png')
|
105
105
|
update_current_game()
|
106
106
|
current_source = get_source_from_scene(get_current_game())
|
107
107
|
current_source_name = current_source.sourceName
|
@@ -12,7 +12,7 @@ vad_model = load_silero_vad()
|
|
12
12
|
# Use Silero to detect voice activity with timestamps in the audio
|
13
13
|
def detect_voice_with_silero(input_audio):
|
14
14
|
# Convert the audio to 16kHz mono WAV
|
15
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.
|
15
|
+
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
16
16
|
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
17
17
|
|
18
18
|
# Load the audio and detect speech timestamps
|
@@ -67,7 +67,7 @@ def download_and_cache_vosk_model(model_dir="vosk_model_cache"):
|
|
67
67
|
def detect_voice_with_vosk(input_audio):
|
68
68
|
global vosk_model_path, vosk_model
|
69
69
|
# Convert the audio to 16kHz mono WAV
|
70
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.
|
70
|
+
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
71
71
|
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
72
72
|
|
73
73
|
if not vosk_model_path or not vosk_model:
|
@@ -24,7 +24,7 @@ def load_whisper_model():
|
|
24
24
|
# Use Whisper to detect voice activity with timestamps in the audio
|
25
25
|
def detect_voice_with_whisper(input_audio):
|
26
26
|
# Convert the audio to 16kHz mono WAV
|
27
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.
|
27
|
+
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
28
28
|
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
29
29
|
|
30
30
|
# Make sure Whisper is loaded
|
@@ -0,0 +1,20 @@
|
|
1
|
+
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
GameSentenceMiner/anki.py,sha256=3UT6K5PxzJMDoiXyOULrkeCoJ0KMq7JvBw6XhcLCirE,9114
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=s03e8F2pEPj0iG31RxFqWGfm2GLb8JoGQR7QhCMFu3M,45581
|
4
|
+
GameSentenceMiner/configuration.py,sha256=7sXYNBNXyezPFbGKTu2XwjMAy6vQ1tJPfLg2aq2UGRA,13859
|
5
|
+
GameSentenceMiner/ffmpeg.py,sha256=hdKimzkpAKsE-17qEAQg4uHy4-TtdFywYx48Skn9cPs,10418
|
6
|
+
GameSentenceMiner/gametext.py,sha256=GpR9P8h3GmmKH46Dw13kJPx66n3jGjFCiV8Fcrqn9E8,3999
|
7
|
+
GameSentenceMiner/gsm.py,sha256=Lnj59KHV4l5eEgffkswBlRCONgYB_Id3L0pTajUzsvI,14937
|
8
|
+
GameSentenceMiner/model.py,sha256=oh8VVT8T1UKekbmP6MGNgQ8jIuQ_7Rg4GPzDCn2kJo8,1999
|
9
|
+
GameSentenceMiner/notification.py,sha256=sWgIIXhaB9WV1K_oQGf5-IR6q3dakae_QS-RuIvbcEs,1939
|
10
|
+
GameSentenceMiner/obs.py,sha256=VH9qXRbmxWxFgcp6iGzEQUseyxf_qINCOM54ByGa7_0,3698
|
11
|
+
GameSentenceMiner/util.py,sha256=OYg0j_rT9F7v3aJRwWnHvdWMYyxGlimrvw7U2C9ifeY,4441
|
12
|
+
GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
GameSentenceMiner/vad/silero_trim.py,sha256=r7bZYEj-NUXGKgD2UIhLrbTPyq0rau97qGtrMZcRK4A,1517
|
14
|
+
GameSentenceMiner/vad/vosk_helper.py,sha256=lWmlGMhmg_0QoWeCHrXwz9wDKPqY37BckHCekGVtJUI,5794
|
15
|
+
GameSentenceMiner/vad/whisper_helper.py,sha256=9kmPeSs6jRcKSVxYY-vtyTcqVUDORR4q1nl8fqxHHn4,3379
|
16
|
+
GameSentenceMiner-2.0.0.dev1.dist-info/METADATA,sha256=32ajZFt816JeijN0hktOxA656mnWWT_5rSnSUK16PjI,13394
|
17
|
+
GameSentenceMiner-2.0.0.dev1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
+
GameSentenceMiner-2.0.0.dev1.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
19
|
+
GameSentenceMiner-2.0.0.dev1.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
20
|
+
GameSentenceMiner-2.0.0.dev1.dist-info/RECORD,,
|
@@ -1,20 +0,0 @@
|
|
1
|
-
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=3UT6K5PxzJMDoiXyOULrkeCoJ0KMq7JvBw6XhcLCirE,9114
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=d1UDXbTNSZBFneWEytqdnySBL-_iJ1MGY0Jvyg3vn80,45691
|
4
|
-
GameSentenceMiner/configuration.py,sha256=ilTnUXFIu9G7folA4AT78M57Wq9-j74gi5MbYWDtDRw,13165
|
5
|
-
GameSentenceMiner/ffmpeg.py,sha256=XreJHjmCpmdI04g_UmTzXmh5pay1s5DLx41nrAJmQwo,10396
|
6
|
-
GameSentenceMiner/gametext.py,sha256=GpR9P8h3GmmKH46Dw13kJPx66n3jGjFCiV8Fcrqn9E8,3999
|
7
|
-
GameSentenceMiner/gsm.py,sha256=4kOb3eIiOZLpRv-ZhczoJ_ZtqMMxnxK0XW9gLWkdK8I,15557
|
8
|
-
GameSentenceMiner/model.py,sha256=oh8VVT8T1UKekbmP6MGNgQ8jIuQ_7Rg4GPzDCn2kJo8,1999
|
9
|
-
GameSentenceMiner/notification.py,sha256=sWgIIXhaB9WV1K_oQGf5-IR6q3dakae_QS-RuIvbcEs,1939
|
10
|
-
GameSentenceMiner/obs.py,sha256=-hGz3D9roCDVecZ9IhIofPppcmTEAYO8cZf-lnkBBxU,3687
|
11
|
-
GameSentenceMiner/util.py,sha256=OYg0j_rT9F7v3aJRwWnHvdWMYyxGlimrvw7U2C9ifeY,4441
|
12
|
-
GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
GameSentenceMiner/vad/silero_trim.py,sha256=x1jTQF9x55Q2HF32xAE4QrLoa30U3ksOmY9XF_qulrs,1506
|
14
|
-
GameSentenceMiner/vad/vosk_helper.py,sha256=6vPkfaj2TJtS0Ph3aUByTx98rb-InKcnhp7MZh-vY-c,5783
|
15
|
-
GameSentenceMiner/vad/whisper_helper.py,sha256=sfGTXU3dt5ZAXMaZbBp3j2cvYc0QF-HXD72_Lgl1NTs,3368
|
16
|
-
GameSentenceMiner-2.0.0.dist-info/METADATA,sha256=m4DB-eNUyyaygdHyAmO7gZVyWcXQijPtxlPc6AVPKzI,13389
|
17
|
-
GameSentenceMiner-2.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
-
GameSentenceMiner-2.0.0.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
19
|
-
GameSentenceMiner-2.0.0.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
20
|
-
GameSentenceMiner-2.0.0.dist-info/RECORD,,
|
File without changes
|
{GameSentenceMiner-2.0.0.dist-info → GameSentenceMiner-2.0.0.dev1.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|