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.
@@ -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('../../config.json', 'w') as file:
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('config.json', 'w') as f:
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('config.json', 'w') as file:
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)
@@ -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.temp_directory,
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.temp_directory,
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.temp_directory)}/{obs.get_current_game(sanitize=True)}.{get_config().audio.extension}")
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
- with tempfile.TemporaryDirectory(dir="../temp_files") as temp_dir:
353
- configuration.temp_directory = temp_dir
354
- event_handler = VideoToAudioHandler()
355
- observer = Observer()
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
- logger.info("Script Initialized. Happy Mining!")
360
- if not is_linux():
361
- register_hotkeys()
348
+ logger.info("Script Initialized. Happy Mining!")
349
+ if not is_linux():
350
+ register_hotkeys()
362
351
 
363
- # Register signal handlers for graceful shutdown
364
- signal.signal(signal.SIGTERM, handle_exit()) # Handle `kill` commands
365
- signal.signal(signal.SIGINT, handle_exit()) # Handle Ctrl+C
366
- win32api.SetConsoleCtrlHandler(handle_exit())
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
- util.run_new_thread(run_tray)
357
+ util.run_new_thread(run_tray)
369
358
 
370
- try:
371
- settings_window = config_gui.ConfigApp()
372
- settings_window.add_save_hook(update_icon)
373
- settings_window.window.mainloop()
374
- except KeyboardInterrupt:
375
- cleanup()
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
- try:
378
- observer.stop()
379
- observer.join()
380
- except Exception as e:
381
- logger.error(f"Error stopping observer: {e}")
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.temp_directory) + '/screenshot.png')
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.temp_directory, suffix='.wav').name
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.temp_directory, suffix='.wav').name
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.temp_directory, suffix='.wav').name
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: GameSentenceMiner
3
- Version: 2.0.0
3
+ Version: 2.0.0.dev1
4
4
  Summary: A tool for mining sentences from games.
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -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,,