GameSentenceMiner 2.5.9__py3-none-any.whl → 2.5.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/anki.py CHANGED
@@ -28,7 +28,7 @@ card_queue = []
28
28
 
29
29
 
30
30
  def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='', tango='', reuse_audio=False,
31
- should_update_audio=True, ss_time=0, game_line=None):
31
+ should_update_audio=True, ss_time=0, game_line=None, selected_lines=None):
32
32
  global audio_in_anki, screenshot_in_anki, prev_screenshot_in_anki
33
33
  update_audio = should_update_audio and (get_config().anki.sentence_audio_field and not
34
34
  last_note.get_field(get_config().anki.sentence_audio_field) or get_config().anki.overwrite_audio)
@@ -44,7 +44,7 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
44
44
  if get_config().paths.remove_screenshot:
45
45
  os.remove(screenshot)
46
46
  if get_config().anki.previous_image_field:
47
- prev_screenshot = ffmpeg.get_screenshot(video_path, ffmpeg.get_screenshot_time(video_path, game_line.prev))
47
+ prev_screenshot = ffmpeg.get_screenshot(video_path, ffmpeg.get_screenshot_time(video_path, selected_lines[0].prev if selected_lines else game_line.prev))
48
48
  prev_screenshot_in_anki = store_media_file(prev_screenshot)
49
49
  if get_config().paths.remove_screenshot:
50
50
  os.remove(prev_screenshot)
@@ -158,7 +158,10 @@ def get_initial_card_info(last_note: AnkiCard, selected_lines):
158
158
  last_note.get_field(get_config().anki.previous_sentence_field):
159
159
  logger.debug(
160
160
  f"Adding Previous Sentence: {get_config().anki.previous_sentence_field and game_line.prev.text and not last_note.get_field(get_config().anki.previous_sentence_field)}")
161
- note['fields'][get_config().anki.previous_sentence_field] = game_line.prev.text
161
+ if selected_lines:
162
+ note['fields'][get_config().anki.previous_sentence_field] = selected_lines[0].prev.text
163
+ else:
164
+ note['fields'][get_config().anki.previous_sentence_field] = game_line.prev.text
162
165
  return note
163
166
 
164
167
 
@@ -216,6 +216,8 @@ class ConfigApp:
216
216
  self.master_config.current_profile = current_profile
217
217
  self.master_config.set_config_for_profile(current_profile, config)
218
218
 
219
+ self.master_config = self.master_config.sync_shared_fields()
220
+
219
221
  # Serialize the config instance to JSON
220
222
  with open(get_config_path(), 'w') as file:
221
223
  file.write(self.master_config.to_json(indent=4))
@@ -225,6 +227,7 @@ class ConfigApp:
225
227
  if self.master_config.get_config().restart_required(prev_config):
226
228
  logger.info("Restart Required for some settings to take affect!")
227
229
  send_restart_signal()
230
+
228
231
  settings_saved = True
229
232
  configuration.reload_config()
230
233
  self.settings = get_config()
@@ -303,6 +303,58 @@ class Config:
303
303
  def get_default_config(self):
304
304
  return self.configs[DEFAULT_CONFIG]
305
305
 
306
+ def sync_shared_fields(self):
307
+ config = self.get_config()
308
+ for profile in self.configs.values():
309
+ self.sync_shared_field(config.hotkeys, profile.hotkeys, "reset_line")
310
+ self.sync_shared_field(config.hotkeys, profile.hotkeys, "take_screenshot")
311
+ self.sync_shared_field(config.hotkeys, profile.hotkeys, "open_utility")
312
+ self.sync_shared_field(config.hotkeys, profile.hotkeys, "play_latest_audio")
313
+ # self.sync_shared_field(config.advanced, profile.advanced, "audio_player_path")
314
+ # self.sync_shared_field(config.advanced, profile.advanced, "video_player_path")
315
+ # self.sync_shared_field(config.advanced, profile.advanced, "show_screenshot_buttons")
316
+ self.sync_shared_field(config.anki, profile.anki, "url")
317
+ self.sync_shared_field(config.anki, profile.anki, "sentence_field")
318
+ self.sync_shared_field(config.anki, profile.anki, "sentence_audio_field")
319
+ self.sync_shared_field(config.anki, profile.anki, "picture_field")
320
+ self.sync_shared_field(config.anki, profile.anki, "word_field")
321
+ self.sync_shared_field(config.anki, profile.anki, "previous_sentence_field")
322
+ self.sync_shared_field(config.anki, profile.anki, "previous_image_field")
323
+ self.sync_shared_field(config.anki, profile.anki, "tags_to_check")
324
+ self.sync_shared_field(config.anki, profile.anki, "add_game_tag")
325
+ self.sync_shared_field(config.anki, profile.anki, "polling_rate")
326
+ self.sync_shared_field(config.anki, profile.anki, "overwrite_audio")
327
+ self.sync_shared_field(config.anki, profile.anki, "overwrite_picture")
328
+ self.sync_shared_field(config.anki, profile.anki, "multi_overwrites_sentence")
329
+ self.sync_shared_field(config.anki, profile.anki, "anki_custom_fields")
330
+ self.sync_shared_field(config.general, profile.general, "open_config_on_startup")
331
+ self.sync_shared_field(config.general, profile.general, "open_multimine_on_startup")
332
+ self.sync_shared_field(config.general, profile.general, "websocket_uri")
333
+ self.sync_shared_field(config.audio, profile.audio, "external_tool")
334
+ self.sync_shared_field(config.audio, profile.audio, "anki_media_collection")
335
+ self.sync_shared_field(config, profile, "advanced")
336
+ self.sync_shared_field(config, profile, "paths")
337
+ self.sync_shared_field(config, profile, "obs")
338
+
339
+ return self
340
+
341
+ def sync_shared_field(self, config, config2, field_name):
342
+ try:
343
+ config_value = getattr(config, field_name, None)
344
+ config2_value = getattr(config2, field_name, None)
345
+
346
+ if config_value != config2_value: # Check if values are different.
347
+ if config_value is not None:
348
+ logging.info(f"Syncing shared field '{field_name}' to other profile.")
349
+ setattr(config2, field_name, config_value)
350
+ elif config2_value is not None:
351
+ logging.info(f"Syncing shared field '{field_name}' to current profile.")
352
+ setattr(config, field_name, config2_value)
353
+ except AttributeError as e:
354
+ logging.error(f"AttributeError during sync of '{field_name}': {e}")
355
+ except Exception as e:
356
+ logging.error(f"An unexpected error occurred during sync of '{field_name}': {e}")
357
+
306
358
 
307
359
  def get_default_anki_path():
308
360
  if platform == 'win32': # Windows
@@ -191,7 +191,7 @@ def trim_audio_based_on_last_line(untrimmed_audio, video_path, game_line, next_l
191
191
 
192
192
  ffmpeg_command = ffmpeg_base_command_list + [
193
193
  "-i", untrimmed_audio,
194
- "-ss", start_trim_time]
194
+ "-ss", str(start_trim_time)]
195
195
  if next_line and next_line > game_line.time:
196
196
  end_total_seconds = total_seconds + (next_line - game_line.time).total_seconds() + 1
197
197
  hours, remainder = divmod(end_total_seconds, 3600)
@@ -222,7 +222,8 @@ def get_video_timings(video_path, game_line):
222
222
  total_seconds = file_length - time_delta.total_seconds()
223
223
  total_seconds_after_offset = total_seconds + get_config().audio.beginning_offset
224
224
  if total_seconds < 0 or total_seconds >= file_length:
225
- logger.info(f"0 seconds trimmed off of beginning")
225
+ logger.error("Line mined is outside of the replay buffer! Defaulting to the beginning of the replay buffer. ")
226
+ logger.info("Recommend either increasing replay buffer length in OBS Settings or mining faster.")
226
227
  return 0, 0, 0
227
228
 
228
229
  hours, remainder = divmod(total_seconds_after_offset, 3600)
GameSentenceMiner/gsm.py CHANGED
@@ -1,3 +1,4 @@
1
+ import os.path
1
2
  import signal
2
3
  import time
3
4
  from subprocess import Popen
@@ -25,6 +26,7 @@ from GameSentenceMiner.configuration import *
25
26
  from GameSentenceMiner.downloader.download_tools import download_obs_if_needed, download_ffmpeg_if_needed
26
27
  from GameSentenceMiner.ffmpeg import get_audio_and_trim, get_video_timings
27
28
  from GameSentenceMiner.gametext import get_text_event, get_mined_line, GameLine
29
+ from GameSentenceMiner.obs import check_obs_folder_is_correct
28
30
  from GameSentenceMiner.util import *
29
31
  from GameSentenceMiner.utility_gui import init_utility_window, get_utility_window
30
32
  from GameSentenceMiner.vad import silero_trim, whisper_helper, vosk_helper
@@ -70,21 +72,27 @@ class VideoToAudioHandler(FileSystemEventHandler):
70
72
 
71
73
  @staticmethod
72
74
  def convert_to_audio(video_path):
73
- if get_utility_window().line_for_audio:
74
- line: GameLine = get_utility_window().line_for_audio
75
- get_utility_window().line_for_audio = None
76
- if get_config().advanced.audio_player_path:
77
- audio = VideoToAudioHandler.get_audio(line, line.next.time if line.next else None, video_path, temporary=True)
78
- play_audio_in_external(audio)
75
+ try:
76
+ if get_utility_window().line_for_audio:
77
+ line: GameLine = get_utility_window().line_for_audio
78
+ get_utility_window().line_for_audio = None
79
+ if get_config().advanced.audio_player_path:
80
+ audio = VideoToAudioHandler.get_audio(line, line.next.time if line.next else None, video_path, temporary=True)
81
+ play_audio_in_external(audio)
82
+ os.remove(video_path)
83
+ elif get_config().advanced.video_player_path:
84
+ play_video_in_external(line, video_path)
85
+ return
86
+ if get_utility_window().line_for_screenshot:
87
+ line: GameLine = get_utility_window().line_for_screenshot
88
+ get_utility_window().line_for_screenshot = None
89
+ screenshot = ffmpeg.get_screenshot_for_line(video_path, line)
90
+ os.startfile(screenshot)
79
91
  os.remove(video_path)
80
- elif get_config().advanced.video_player_path:
81
- play_video_in_external(line, video_path)
82
- return
83
- if get_utility_window().line_for_screenshot:
84
- line: GameLine = get_utility_window().line_for_screenshot
85
- get_utility_window().line_for_screenshot = None
86
- screenshot = ffmpeg.get_screenshot_for_line(video_path, line)
87
- os.startfile(screenshot)
92
+ return
93
+ except Exception as e:
94
+ logger.error(f"Error Playing Audio/Video: {e}")
95
+ logger.debug(f"Error Playing Audio/Video: {e}", exc_info=True)
88
96
  os.remove(video_path)
89
97
  return
90
98
  try:
@@ -128,8 +136,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
128
136
  ss_timing = ffmpeg.get_screenshot_time(video_path, mined_line)
129
137
  if last_note:
130
138
  logger.debug(last_note.to_json())
131
-
132
- note = anki.get_initial_card_info(last_note, get_utility_window().get_selected_lines())
139
+ selected_lines = get_utility_window().get_selected_lines()
140
+ note = anki.get_initial_card_info(last_note, selected_lines)
133
141
  tango = last_note.get_field(get_config().anki.word_field) if last_note else ''
134
142
  get_utility_window().reset_checkboxes()
135
143
 
@@ -149,17 +157,19 @@ class VideoToAudioHandler(FileSystemEventHandler):
149
157
  tango=tango,
150
158
  should_update_audio=should_update_audio,
151
159
  ss_time=ss_timing,
152
- game_line=start_line)
160
+ game_line=start_line,
161
+ selected_lines=selected_lines)
153
162
  elif get_config().features.notify_on_update and should_update_audio:
154
163
  notification.send_audio_generated_notification(vad_trimmed_audio)
155
164
  except Exception as e:
156
165
  logger.error(f"Failed Processing and/or adding to Anki: Reason {e}")
157
166
  logger.debug(f"Some error was hit catching to allow further work to be done: {e}", exc_info=True)
158
167
  notification.send_error_no_anki_update()
159
- if get_config().paths.remove_video and os.path.exists(video_path):
160
- os.remove(video_path) # Optionally remove the video after conversion
161
- if get_config().paths.remove_audio and os.path.exists(vad_trimmed_audio):
162
- os.remove(vad_trimmed_audio) # Optionally remove the screenshot after conversion
168
+ finally:
169
+ if get_config().paths.remove_video and os.path.exists(video_path):
170
+ os.remove(video_path) # Optionally remove the video after conversion
171
+ if get_config().paths.remove_audio and os.path.exists(vad_trimmed_audio):
172
+ os.remove(vad_trimmed_audio) # Optionally remove the screenshot after conversion
163
173
 
164
174
 
165
175
  @staticmethod
@@ -226,18 +236,17 @@ def play_video_in_external(line, filepath):
226
236
 
227
237
  start, _, _ = get_video_timings(filepath, line)
228
238
 
229
- print(start)
230
-
231
- if "vlc" in get_config().advanced.video_player_path:
232
- command.append("--start-time")
233
- else:
234
- command.append("--start")
235
-
236
- command.extend([convert_to_vlc_seconds(start), os.path.normpath(filepath)])
239
+ if start:
240
+ if "vlc" in get_config().advanced.video_player_path:
241
+ command.append("--start-time")
242
+ else:
243
+ command.append("--start")
244
+ command.append(convert_to_vlc_seconds(start))
245
+ command.append(os.path.normpath(filepath))
237
246
 
238
247
  try:
239
248
  proc = subprocess.Popen(command)
240
- print(f"Opened {filepath} in VLC.")
249
+ print(f"Opened {filepath} in {get_config().advanced.video_player_path}.")
241
250
  threading.Thread(target=remove_video_when_closed, args=(proc, filepath)).start()
242
251
  except FileNotFoundError:
243
252
  print("VLC not found. Make sure it's installed and in your PATH.")
@@ -535,7 +544,8 @@ def initialize_async():
535
544
  if get_config().obs.enabled:
536
545
  if get_config().obs.open_obs:
537
546
  tasks.append(obs.start_obs)
538
- tasks.append(obs.connect_to_obs)
547
+ else:
548
+ tasks.append(obs.connect_to_obs)
539
549
  tasks.append(anki.start_monitoring_anki)
540
550
  if get_config().vad.do_vad_postprocessing:
541
551
  if VOSK in (get_config().vad.backup_vad_model, get_config().vad.selected_vad_model):
@@ -571,6 +581,7 @@ def main(reloading=False):
571
581
  init_utility_window(root)
572
582
  initialize(reloading)
573
583
  initialize_async()
584
+ check_obs_folder_is_correct()
574
585
  observer = Observer()
575
586
  observer.schedule(VideoToAudioHandler(), get_config().paths.folder_to_watch, recursive=False)
576
587
  observer.start()
@@ -77,6 +77,12 @@ class SceneItemsResponse:
77
77
  # def __init__(self, **kwargs):
78
78
  # self.sceneItems = [SceneItem(**item) for item in kwargs['sceneItems']]
79
79
 
80
+
81
+ @dataclass_json
82
+ @dataclass
83
+ class RecordDirectory:
84
+ recordDirectory: str
85
+
80
86
  #
81
87
  # @dataclass_json
82
88
  # @dataclass
@@ -6,9 +6,17 @@ from win10toast import ToastNotifier
6
6
 
7
7
  from GameSentenceMiner.configuration import logger
8
8
 
9
+ class MyToastNotifier(ToastNotifier):
10
+ def __init__(self):
11
+ super().__init__()
12
+
13
+ def on_destroy(self, hwnd, msg, wparam, lparam):
14
+ super().on_destroy(hwnd, msg, wparam, lparam)
15
+ return 0
16
+
9
17
  system = platform.system()
10
18
  if system == "Windows":
11
- notifier = ToastNotifier()
19
+ notifier = MyToastNotifier()
12
20
  else:
13
21
  notifier = notification
14
22
 
GameSentenceMiner/obs.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import os.path
2
3
  import subprocess
3
4
  import time
4
5
 
@@ -32,11 +33,21 @@ def start_obs():
32
33
  return obs_pid
33
34
  obs_process = subprocess.Popen([obs_path, '--disable-shutdown-check', '--portable'], cwd=os.path.dirname(obs_path))
34
35
  logger.info("OBS launched")
36
+ connect_to_obs()
35
37
  return obs_process.pid
36
38
  except Exception as e:
37
39
  logger.error(f"Error launching OBS: {e}")
38
40
  return None
39
41
 
42
+ def check_obs_folder_is_correct():
43
+ obs_record_directory = get_record_directory()
44
+ if obs_record_directory and os.path.normpath(obs_record_directory) != os.path.normpath(
45
+ get_config().paths.folder_to_watch):
46
+ logger.info("OBS Path Setting wrong, OBS Recording folder in GSM Config")
47
+ get_config().paths.folder_to_watch = os.path.normpath(obs_record_directory)
48
+ get_master_config().sync_shared_fields()
49
+ save_full_config(get_master_config())
50
+
40
51
  def is_obs_running(obs_path):
41
52
  obs_path = os.path.abspath(obs_path) # Normalize path
42
53
  for process in psutil.process_iter(['exe']):
@@ -114,7 +125,7 @@ def disconnect_from_obs():
114
125
  client = None
115
126
  logger.info("Disconnected from OBS WebSocket.")
116
127
 
117
- def do_obs_call(request, from_dict = None, retry=5):
128
+ def do_obs_call(request, from_dict = None, retry=10):
118
129
  try:
119
130
  response = client.call(request)
120
131
  if not response.status and retry > 0:
@@ -163,14 +174,13 @@ def stop_replay_buffer():
163
174
  except Exception as e:
164
175
  logger.error(f"Error stopping replay buffer: {e}")
165
176
 
166
-
167
177
  # Save the current replay buffer
168
178
  def save_replay_buffer():
169
179
  try:
170
180
  replay_buffer_started = client.call(requests.GetReplayBufferStatus()).datain['outputActive']
171
181
  if replay_buffer_started:
172
182
  client.call(requests.SaveReplayBuffer())
173
- logger.info("Replay buffer saved.")
183
+ logger.info("Replay buffer saved. If your log stops bere, make sure your obs output path matches \"Path To Watch\" in GSM settings.")
174
184
  else:
175
185
  logger.error("Replay Buffer is not active, could not save Replay Buffer!")
176
186
  except Exception as e:
@@ -192,6 +202,13 @@ def get_source_from_scene(scene_name):
192
202
  logger.error(f"Error getting source from scene: {e}")
193
203
  return ''
194
204
 
205
+ def get_record_directory():
206
+ try:
207
+ return do_obs_call(requests.GetRecordDirectory(), RecordDirectory.from_dict).recordDirectory
208
+ except Exception as e:
209
+ logger.error(f"Error getting recording folder: {e}")
210
+ return ''
211
+
195
212
 
196
213
  def get_screenshot():
197
214
  try:
@@ -78,8 +78,12 @@ class UtilityApp:
78
78
 
79
79
  def add_text(self, line):
80
80
  if line.text:
81
- var = tk.BooleanVar()
82
- self.items.append((line, var))
81
+ try:
82
+ var = tk.BooleanVar()
83
+ self.items.append((line, var))
84
+ except Exception as e:
85
+ logger.error(f"NOT AN ERROR: Attempted to add text to multi-mine window, before it was initialized: {e}")
86
+ return
83
87
 
84
88
  if len(self.items) > 10:
85
89
  if self.checkboxes:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.5.9
3
+ Version: 2.5.11
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
@@ -0,0 +1,29 @@
1
+ GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ GameSentenceMiner/anki.py,sha256=xeWU1jX1ZK6tZVnDPqhBzetkCxdbPUWG1LkUy0sfHVg,13089
3
+ GameSentenceMiner/config_gui.py,sha256=v4XRxGqRddqCrdv1UHu4Gnp7aMjL-CCCHBFlTy1Y2v0,61265
4
+ GameSentenceMiner/configuration.py,sha256=DXlwEV4A7X3yzVV6UomY2jmmYAZx_jjMRxZeweoCtRE,20149
5
+ GameSentenceMiner/ffmpeg.py,sha256=fzOxrn-a4KqFdUY2oove164CTDOSsdPQtzqRW5f1P7c,12002
6
+ GameSentenceMiner/gametext.py,sha256=LORVdE2WEo1CDI8gonc7qxrhbS4KFKXFQVKjhlkpLbc,7368
7
+ GameSentenceMiner/gsm.py,sha256=XZLc_HwA8Zzxas0M0oFYbjRwgXa7OLPhT2QXhoiUVzQ,25125
8
+ GameSentenceMiner/model.py,sha256=JdnkT4VoPOXmOpRgFdvERZ09c9wLN6tUJxdrKlGZcqo,5305
9
+ GameSentenceMiner/notification.py,sha256=FY39ChSRK0Y8TQ6lBGsLnpZUFPtFpSy2tweeXVoV7kc,2809
10
+ GameSentenceMiner/obs.py,sha256=EcgQ0VdeYXGeXCyvk8mBiHBL-HHai037BoCXomH9ge4,8239
11
+ GameSentenceMiner/package.py,sha256=YlS6QRMuVlm6mdXx0rlXv9_3erTGS21jaP3PNNWfAH0,1250
12
+ GameSentenceMiner/util.py,sha256=tkaoU1bj8iPMTNwUCWUzFLAnT44Ot92D1tYwQMEnARw,7336
13
+ GameSentenceMiner/utility_gui.py,sha256=H4aOddlsrVR768RwbMzYScCziuOz1JeySUigNrPlaac,7692
14
+ GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
15
+ GameSentenceMiner/communication/send.py,sha256=oOJdCS6-LNX90amkRn5FL2xqx6THGm56zHR2ntVIFTE,229
16
+ GameSentenceMiner/communication/websocket.py,sha256=vrZ9KwRUyZOepjayJkxZZTsNIbHGcDLgDRO9dNDwizM,2914
17
+ GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
18
+ GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ GameSentenceMiner/downloader/download_tools.py,sha256=mI1u_FGBmBqDIpCH3jOv8DOoZ3obgP5pIf9o9SVfX2Q,8131
20
+ GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ GameSentenceMiner/vad/silero_trim.py,sha256=-thDIZLuTLra3YBj7WR16Z6JeDgSpge2YuahprBvD8I,1585
22
+ GameSentenceMiner/vad/vosk_helper.py,sha256=BI_mg_qyrjNbuEJjXSUDoV0FWEtQtEOAPmrrNixnZ_8,5974
23
+ GameSentenceMiner/vad/whisper_helper.py,sha256=OF4J8TPPoKPJR1uFwrWAZ2Q7v0HJkVvNGmF8l1tACX0,3447
24
+ gamesentenceminer-2.5.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
25
+ gamesentenceminer-2.5.11.dist-info/METADATA,sha256=7yFwFF9yNCL_KdU8_aYpg6BeWpiQKBjWD1sm6Scl9UI,5436
26
+ gamesentenceminer-2.5.11.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
27
+ gamesentenceminer-2.5.11.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
28
+ gamesentenceminer-2.5.11.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
29
+ gamesentenceminer-2.5.11.dist-info/RECORD,,
@@ -1,29 +0,0 @@
1
- GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- GameSentenceMiner/anki.py,sha256=YcdNDpUskjdxi8upZ5SLGTyRbO8NlOPcqsV_8akTwuM,12877
3
- GameSentenceMiner/config_gui.py,sha256=cLKVliB0X61WNduNisOmaEtqSr1mvTO6ZAiv-t2jW-8,61194
4
- GameSentenceMiner/configuration.py,sha256=-b1wW6EkkOFwF1No1uZLD2nPUV5gfBIzG5a8_ykqyUI,16691
5
- GameSentenceMiner/ffmpeg.py,sha256=Bvkk0TMHtoQkpEYQls48CbC4TB0-FzrnqQhRNg36hVk,11831
6
- GameSentenceMiner/gametext.py,sha256=LORVdE2WEo1CDI8gonc7qxrhbS4KFKXFQVKjhlkpLbc,7368
7
- GameSentenceMiner/gsm.py,sha256=FahSpCMBQGZjbROTfrDFUrELJ09TvOKCsWKFXpeuaIU,24473
8
- GameSentenceMiner/model.py,sha256=bZm-2vkIw4gQCGLB02eDoTtO1Ymb_dnHk0VDJDFO3y8,5228
9
- GameSentenceMiner/notification.py,sha256=2d8_8DUxImeC1zY-V4c_PZw1zbvvGZ6KiAnPaSmH9G0,2592
10
- GameSentenceMiner/obs.py,sha256=N7XoPSzLk9rHi4sgsG_LS2dN06MrqwN2mpSHfjONTjE,7368
11
- GameSentenceMiner/package.py,sha256=YlS6QRMuVlm6mdXx0rlXv9_3erTGS21jaP3PNNWfAH0,1250
12
- GameSentenceMiner/util.py,sha256=tkaoU1bj8iPMTNwUCWUzFLAnT44Ot92D1tYwQMEnARw,7336
13
- GameSentenceMiner/utility_gui.py,sha256=aVdI9zVXADS53g7QtTgmkVK1LumBsXF4Lou3qJzgHN8,7487
14
- GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
15
- GameSentenceMiner/communication/send.py,sha256=oOJdCS6-LNX90amkRn5FL2xqx6THGm56zHR2ntVIFTE,229
16
- GameSentenceMiner/communication/websocket.py,sha256=vrZ9KwRUyZOepjayJkxZZTsNIbHGcDLgDRO9dNDwizM,2914
17
- GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
18
- GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- GameSentenceMiner/downloader/download_tools.py,sha256=mI1u_FGBmBqDIpCH3jOv8DOoZ3obgP5pIf9o9SVfX2Q,8131
20
- GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- GameSentenceMiner/vad/silero_trim.py,sha256=-thDIZLuTLra3YBj7WR16Z6JeDgSpge2YuahprBvD8I,1585
22
- GameSentenceMiner/vad/vosk_helper.py,sha256=BI_mg_qyrjNbuEJjXSUDoV0FWEtQtEOAPmrrNixnZ_8,5974
23
- GameSentenceMiner/vad/whisper_helper.py,sha256=OF4J8TPPoKPJR1uFwrWAZ2Q7v0HJkVvNGmF8l1tACX0,3447
24
- gamesentenceminer-2.5.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
25
- gamesentenceminer-2.5.9.dist-info/METADATA,sha256=tQ1mZZNVR5H06FYNkgokrzWUd7IZW6piZtR6GlPbDDs,5435
26
- gamesentenceminer-2.5.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
27
- gamesentenceminer-2.5.9.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
28
- gamesentenceminer-2.5.9.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
29
- gamesentenceminer-2.5.9.dist-info/RECORD,,