GameSentenceMiner 2.9.16__py3-none-any.whl → 2.9.18__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 CHANGED
@@ -279,14 +279,14 @@ def play_video_in_external(line, filepath):
279
279
 
280
280
  command = [get_config().advanced.video_player_path]
281
281
 
282
- start, _, _, _ = get_video_timings(filepath, line)
282
+ start, _, _, _ = get_video_timings(new_filepath, line)
283
283
 
284
284
  if start:
285
285
  if "vlc" in get_config().advanced.video_player_path:
286
286
  command.extend(["--start-time", convert_to_vlc_seconds(start), '--one-instance'])
287
287
  else:
288
288
  command.extend(["--start", convert_to_vlc_seconds(start)])
289
- command.append(os.path.normpath(filepath))
289
+ command.append(os.path.normpath(new_filepath))
290
290
 
291
291
  logger.info(" ".join(command))
292
292
 
GameSentenceMiner/obs.py CHANGED
@@ -29,12 +29,12 @@ class OBSConnectionManager(threading.Thread):
29
29
  while self.running:
30
30
  time.sleep(1)
31
31
  try:
32
- if not client or not client.get_version() and not connecting:
33
- logger.info("OBS WebSocket not connected. Attempting to reconnect...")
34
- gsm_status.obs_connected = False
35
- asyncio.run(connect_to_obs())
32
+ if not connecting:
33
+ client.get_version()
36
34
  except Exception as e:
37
- logger.debug(f"Error checking OBS connection: {e}")
35
+ logger.info(f"OBS WebSocket not connected. Attempting to reconnect... {e}")
36
+ gsm_status.obs_connected = False
37
+ asyncio.run(connect_to_obs())
38
38
 
39
39
  def stop(self):
40
40
  self.running = False
@@ -124,7 +124,7 @@ def get_screenshot_for_line(video_file, game_line, try_selector=False):
124
124
  return get_screenshot(video_file, get_screenshot_time(video_file, game_line), try_selector)
125
125
 
126
126
 
127
- def get_screenshot_time(video_path, game_line, default_beginning=False, vad_result=None, doing_multi_line=False, previous_line=False):
127
+ def get_screenshot_time(video_path, game_line, default_beginning=False, vad_result=None, doing_multi_line=False, previous_line=False, anki_card_creation_time=0):
128
128
  if game_line:
129
129
  line_time = game_line.time
130
130
  else:
@@ -136,7 +136,10 @@ def get_screenshot_time(video_path, game_line, default_beginning=False, vad_resu
136
136
  logger.debug("Calculating screenshot time for line: " + str(game_line.text))
137
137
 
138
138
  file_length = get_video_duration(video_path)
139
- file_mod_time = get_file_modification_time(video_path)
139
+ if anki_card_creation_time:
140
+ file_mod_time = anki_card_creation_time
141
+ else:
142
+ file_mod_time = get_file_modification_time(video_path)
140
143
 
141
144
  # Calculate when the line occurred within the video file (seconds from start)
142
145
  time_delta = file_mod_time - line_time
@@ -279,6 +282,83 @@ def get_audio_and_trim(video_path, game_line, next_line_time, anki_card_creation
279
282
 
280
283
  return trim_audio_based_on_last_line(untrimmed_audio, video_path, game_line, next_line_time, anki_card_creation_time)
281
284
 
285
+ def get_audio_and_trim_combined(video_path, game_line, next_line_time, anki_card_creation_time):
286
+ supported_formats = {
287
+ 'opus': 'libopus',
288
+ 'mp3': 'libmp3lame',
289
+ 'ogg': 'libvorbis',
290
+ 'aac': 'aac',
291
+ 'm4a': 'aac',
292
+ }
293
+
294
+ codec = get_audio_codec(video_path)
295
+ output_extension = get_config().audio.extension
296
+ output_audio_path = tempfile.NamedTemporaryFile(
297
+ dir=configuration.get_temporary_directory(),
298
+ suffix=f".{output_extension}",
299
+ delete=False
300
+ ).name
301
+
302
+ if codec == output_extension:
303
+ codec_command = ['-c:a', 'copy']
304
+ logger.debug(f"Extracting {output_extension} from video (copying)")
305
+ else:
306
+ codec_command = ["-c:a", f"{supported_formats[output_extension]}"]
307
+ logger.debug(f"Re-encoding {codec} to {output_extension}")
308
+
309
+ start_trim_time, start_time_float, total_seconds_after_offset, file_length = get_video_timings(video_path, game_line, anki_card_creation_time)
310
+
311
+ ffmpeg_command = ffmpeg_base_command_list + [
312
+ "-ss", str(start_trim_time),
313
+ "-i", video_path,
314
+ "-map", "0:a"
315
+ ]
316
+
317
+ end_trim_time_str = ""
318
+
319
+ if next_line_time and next_line_time > game_line.time:
320
+ end_total_seconds = next_line_time + get_config().audio.pre_vad_end_offset
321
+ hours, remainder = divmod(end_total_seconds, 3600)
322
+ minutes, seconds = divmod(remainder, 60)
323
+ end_trim_time_str = "{:02}:{:02}:{:06.3f}".format(int(hours), int(minutes), seconds)
324
+ ffmpeg_command.extend(['-to', end_trim_time_str])
325
+ logger.debug(
326
+ f"Trimming end of audio to {end_trim_time_str} based on next line time.")
327
+ elif get_config().audio.pre_vad_end_offset is not None and get_config().audio.pre_vad_end_offset < 0:
328
+ end_total_seconds = file_length + get_config().audio.pre_vad_end_offset
329
+ end_total_seconds = max(end_total_seconds, start_time_float)
330
+
331
+ hours, remainder = divmod(end_total_seconds, 3600)
332
+ minutes, seconds = divmod(remainder, 60)
333
+ end_trim_time_str = "{:02}:{:02}:{:06.3f}".format(int(hours), int(minutes), seconds)
334
+ ffmpeg_command.extend(['-to', end_trim_time_str])
335
+ logger.debug(f"Trimming end of audio to {end_trim_time_str} due to negative pre-vad end offset.")
336
+
337
+ ffmpeg_command.extend(codec_command)
338
+ ffmpeg_command.append(output_audio_path)
339
+
340
+ logger.debug("Executing combined audio extraction and trimming command")
341
+ logger.debug(" ".join(ffmpeg_command))
342
+
343
+ try:
344
+ subprocess.run(ffmpeg_command, check=True)
345
+ logger.debug(f"{total_seconds_after_offset} trimmed off of beginning")
346
+
347
+ if end_trim_time_str:
348
+ logger.info(f"Audio Extracted and trimmed to {start_trim_time} seconds with end time {end_trim_time_str}")
349
+ else:
350
+ logger.info(f"Audio Extracted and trimmed to {start_trim_time} seconds (to end of file)")
351
+
352
+ logger.debug(f"Audio trimmed and saved to {output_audio_path}")
353
+ return output_audio_path
354
+ except subprocess.CalledProcessError as e:
355
+ logger.error(f"FFmpeg command failed: {e}")
356
+ logger.error(f"Command: {' '.join(ffmpeg_command)}")
357
+ raise
358
+ except Exception as e:
359
+ logger.error(f"An unexpected error occurred: {e}")
360
+ raise
361
+
282
362
 
283
363
  def get_video_duration(file_path):
284
364
  ffprobe_command = [
@@ -339,7 +419,7 @@ def trim_audio_based_on_last_line(untrimmed_audio, video_path, game_line, next_l
339
419
  return trimmed_audio
340
420
 
341
421
  def get_video_timings(video_path, game_line, anki_card_creation_time=None):
342
- if anki_card_creation_time and get_config().advanced.use_anki_note_creation_time:
422
+ if anki_card_creation_time:
343
423
  file_mod_time = anki_card_creation_time
344
424
  else:
345
425
  file_mod_time = get_file_modification_time(video_path)
@@ -296,7 +296,6 @@ def play_audio():
296
296
 
297
297
  @app.route('/get_status', methods=['GET'])
298
298
  def get_status():
299
- gsm_status.clipboard_enabled
300
299
  return jsonify(gsm_status.to_dict()), 200
301
300
 
302
301
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.9.16
3
+ Version: 2.9.18
4
4
  Summary: A tool for mining sentences from games.
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -2,8 +2,8 @@ GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
2
2
  GameSentenceMiner/anki.py,sha256=hNHBIoJRrsWIhLe0sehOYPXTWzPREeXl4gYCPHUCaiE,16331
3
3
  GameSentenceMiner/config_gui.py,sha256=iAOLD47sQW67kzBcZKSQ0Dwctc1ngZK1lwSVIaLpQPI,83559
4
4
  GameSentenceMiner/gametext.py,sha256=iO1o2980XBzBc2nsgBVr_ZaKHRLotebVpDhwGqBCK9k,6696
5
- GameSentenceMiner/gsm.py,sha256=j6Y4Nd79Qi09r-Pgt2y3THxeP-yBAfZSFbbsISE9Ah8,29251
6
- GameSentenceMiner/obs.py,sha256=21GQ4DzjccLc-m4rU5Tfm4E3n1R1U4vRwmIWfKqcjmw,14805
5
+ GameSentenceMiner/gsm.py,sha256=MFptrbACty8wP3dCSb8VLSBmoTsiBUvomJgAcIpBZw4,29259
6
+ GameSentenceMiner/obs.py,sha256=YG8LwBf9BTsGbROm_Uq6LhFDSrbf3jgogp78rBbJq94,14728
7
7
  GameSentenceMiner/vad.py,sha256=TbP3NVdjfB1TFJeB0QpOXZysgo_UHHKLdx95pYmM0JI,14902
8
8
  GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  GameSentenceMiner/ai/ai_prompting.py,sha256=0jBAnngNwmc3dqJiVWe_QRy4Syr-muV-ML2rq0FiUtU,10215
@@ -30,7 +30,7 @@ GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSd
30
30
  GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  GameSentenceMiner/util/configuration.py,sha256=Wgr1UAf_JoXBlp9h_f3-d2DAmIWnR1FtCmMX6mCfMNM,27461
32
32
  GameSentenceMiner/util/electron_config.py,sha256=3VmIrcXhC-wIMMc4uqV85NrNenRl4ZUbnQfSjWEwuig,9852
33
- GameSentenceMiner/util/ffmpeg.py,sha256=daItJprEqi5PQe-aFb836rls3tBHNqIQKz61vlJK07M,19276
33
+ GameSentenceMiner/util/ffmpeg.py,sha256=Z3lD5jd7P59-aNWIQDgovwmjT1kCo4-7DLxoG_VBU4M,22618
34
34
  GameSentenceMiner/util/gsm_utils.py,sha256=Z_Lu4jSIfUaM2VljIJXQkSJD0UsyJ5hMB46H2NS0gZo,8819
35
35
  GameSentenceMiner/util/model.py,sha256=iDtLTfR6D-ZC0gCiDqYno6-gA6Z07PZTM4B5MAA6xZI,5704
36
36
  GameSentenceMiner/util/notification.py,sha256=0OnEYjn3DUEZ6c6OtPjdVZe-DG-QSoMAl9fetjjCvNU,3874
@@ -45,7 +45,7 @@ GameSentenceMiner/util/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
45
45
  GameSentenceMiner/util/downloader/download_tools.py,sha256=mvnOjDHFlV1AbjHaNI7mdnC5_CH5k3N4n1ezqzzbzGA,8139
46
46
  GameSentenceMiner/util/downloader/oneocr_dl.py,sha256=o3ANp5IodEQoQ8GPcJdg9Y8JzA_lictwnebFPwwUZVk,10144
47
47
  GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- GameSentenceMiner/web/texthooking_page.py,sha256=kDRNeTz6eIzc9rqrnupAqEmdVF3GuhB1PSgv9azEaAI,15191
48
+ GameSentenceMiner/web/texthooking_page.py,sha256=d3OiPPgxZ4H5wIh9HrlZutDSiwY3ayvMNrY4c0PdRAE,15158
49
49
  GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
51
51
  GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
@@ -59,9 +59,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
59
59
  GameSentenceMiner/web/templates/index.html,sha256=HZKiIjiGJV8PGQ9T2aLDUNSfJn71qOwbYCjbRuSIjpY,213583
60
60
  GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
61
61
  GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
62
- gamesentenceminer-2.9.16.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
63
- gamesentenceminer-2.9.16.dist-info/METADATA,sha256=ybDsHKiVvTzpQUq5v7g8XQa8NKmf0Vl0Pcsuw18DXIo,7221
64
- gamesentenceminer-2.9.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
- gamesentenceminer-2.9.16.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
66
- gamesentenceminer-2.9.16.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
67
- gamesentenceminer-2.9.16.dist-info/RECORD,,
62
+ gamesentenceminer-2.9.18.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
63
+ gamesentenceminer-2.9.18.dist-info/METADATA,sha256=wgfdfg6X6daqvG3SlEiFlFgU_TVV8QPBpmBl57eV-_4,7221
64
+ gamesentenceminer-2.9.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
+ gamesentenceminer-2.9.18.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
66
+ gamesentenceminer-2.9.18.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
67
+ gamesentenceminer-2.9.18.dist-info/RECORD,,