GameSentenceMiner 2.2.2.post2__py3-none-any.whl → 2.2.4__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
@@ -107,7 +107,7 @@ def get_initial_card_info(last_note):
107
107
  note = {'id': last_note['noteId'], 'fields': {}}
108
108
  if not last_note:
109
109
  return note
110
- current_line, previous_line = get_last_two_sentences()
110
+ current_line, previous_line = get_last_two_sentences(last_note)
111
111
  logger.debug(f"Previous Sentence {previous_line}")
112
112
  logger.debug(f"Current Sentence {current_line}")
113
113
  util.use_previous_audio = True
@@ -200,7 +200,6 @@ def check_for_new_cards():
200
200
  def update_new_card():
201
201
  last_card = get_last_anki_card()
202
202
  if not check_tags_for_should_update(last_card):
203
- logger.info("Card not tagged properly! Not updating!")
204
203
  return
205
204
 
206
205
  use_prev_audio = util.use_previous_audio
@@ -222,11 +221,11 @@ def check_tags_for_should_update(last_card):
222
221
  if get_config().anki.tags_to_check:
223
222
  found = False
224
223
  for tag in last_card['tags']:
225
- logger.info(tag)
226
- logger.info(get_config().anki.tags_to_check)
227
224
  if tag.lower() in get_config().anki.tags_to_check:
228
225
  found = True
229
226
  break
227
+ if not found:
228
+ logger.info(f"Card not tagged properly! Not updating! Note Tags: {last_card['tags']}, Tags_To_Check {get_config().anki.tags_to_check}")
230
229
  return found
231
230
  else:
232
231
  return True
@@ -1,14 +1,16 @@
1
1
  import tkinter as tk
2
2
  from tkinter import filedialog, messagebox, simpledialog
3
3
 
4
+ import pyperclip
4
5
  import ttkbootstrap as ttk
5
6
 
6
- from GameSentenceMiner.package_updater import check_for_updates, get_latest_version, update, get_current_version
7
+ from GameSentenceMiner.package_updater import check_for_updates, get_latest_version, get_current_version
7
8
  from GameSentenceMiner import obs, configuration
8
9
  from GameSentenceMiner.configuration import *
9
10
 
10
11
  settings_saved = False
11
12
  on_save = []
13
+ exit_func = None
12
14
 
13
15
 
14
16
  def new_tab(func):
@@ -45,6 +47,7 @@ class HoverInfoWidget:
45
47
  self.tooltip = None
46
48
 
47
49
 
50
+
48
51
  class ConfigApp:
49
52
  def __init__(self):
50
53
  self.window = ttk.Window(themename='darkly')
@@ -75,7 +78,12 @@ class ConfigApp:
75
78
 
76
79
  self.window.withdraw()
77
80
 
81
+ def add_save_hook(self, func):
82
+ on_save.append(func)
78
83
 
84
+ def add_exit_hook(self, func):
85
+ global exit_func
86
+ exit_func = func
79
87
 
80
88
  def show(self):
81
89
  obs.update_current_game()
@@ -93,9 +101,8 @@ class ConfigApp:
93
101
  update_available, version = check_for_updates()
94
102
  if update_available:
95
103
  messagebox.showinfo("Update", "GSM Will Copy the Update Command to your clipboard, please run it in a terminal.")
96
- success = update()
97
- if not success:
98
- messagebox.showinfo("Update Unsuccessful", "Couldn't Start Update, please update manually.")
104
+ pyperclip.copy("pip install --upgrade GameSentenceMiner")
105
+ exit_func(None, None)
99
106
  else:
100
107
  messagebox.showinfo("No Update Found", "No update found.")
101
108
 
@@ -109,9 +116,6 @@ class ConfigApp:
109
116
  elif show_no_update:
110
117
  messagebox.showinfo("No Update Found", "No update found.")
111
118
 
112
- def add_save_hook(self, func):
113
- on_save.append(func)
114
-
115
119
  def save_settings(self, profile_change=False):
116
120
  global settings_saved
117
121
 
@@ -139,6 +143,7 @@ class ConfigApp:
139
143
  picture_field=self.picture_field.get(),
140
144
  word_field=self.word_field.get(),
141
145
  previous_sentence_field=self.previous_sentence_field.get(),
146
+ previous_image_field=self.previous_image_field.get(),
142
147
  custom_tags=[tag.strip() for tag in self.custom_tags.get().split(',') if tag.strip()],
143
148
  tags_to_check=[tag.strip().lower() for tag in self.tags_to_check.get().split(',') if tag.strip()],
144
149
  add_game_tag=self.add_game_tag.get(),
@@ -476,6 +481,15 @@ class ConfigApp:
476
481
  row=self.current_row,
477
482
  column=2)
478
483
 
484
+ ttk.Label(anki_frame, text="Previous Image Field:").grid(row=self.current_row, column=0, sticky='W')
485
+ self.previous_image_field = ttk.Entry(anki_frame)
486
+ self.previous_image_field.insert(0, self.settings.anki.previous_image_field)
487
+ self.previous_image_field.grid(row=self.current_row, column=1)
488
+ self.add_label_and_increment_row(anki_frame,
489
+ "Field in Anki for the image line of previous Image. If Empty, will not populate",
490
+ row=self.current_row,
491
+ column=2)
492
+
479
493
  ttk.Label(anki_frame, text="Custom Tags:").grid(row=self.current_row, column=0, sticky='W')
480
494
  self.custom_tags = ttk.Entry(anki_frame)
481
495
  self.custom_tags.insert(0, ', '.join(self.settings.anki.custom_tags))
@@ -813,7 +827,7 @@ class ConfigApp:
813
827
  def add_profile(self):
814
828
  new_profile_name = simpledialog.askstring("Input", "Enter new profile name:")
815
829
  if new_profile_name:
816
- self.master_config.configs[new_profile_name] = self.master_config.default_config
830
+ self.master_config.configs[new_profile_name] = self.master_config.get_default_config()
817
831
  self.profile_combobox['values'] = list(self.master_config.configs.keys())
818
832
  self.profile_combobox.set(new_profile_name)
819
833
  self.save_settings()
@@ -64,6 +64,7 @@ class Anki:
64
64
  picture_field: str = "Picture"
65
65
  word_field: str = 'Word'
66
66
  previous_sentence_field: str = ''
67
+ previous_image_field: str = ''
67
68
  custom_tags: List[str] = None # Initialize to None and set it in __post_init__
68
69
  tags_to_check: List[str] = None
69
70
  add_game_tag: bool = True
@@ -249,6 +250,9 @@ class Config:
249
250
  def get_all_profile_names(self):
250
251
  return list(self.configs.keys())
251
252
 
253
+ def get_default_config(self):
254
+ return self.configs[DEFAULT_CONFIG]
255
+
252
256
 
253
257
  def get_app_directory():
254
258
  if platform == 'win32': # Windows
@@ -112,7 +112,7 @@ def get_line_timing(last_note):
112
112
  if sentence:
113
113
  for i, (line, clip_time) in enumerate(reversed(line_history.items())):
114
114
  similarity = similar(remove_html_tags(sentence), line)
115
- if similarity >= 0.60: # 80% similarity threshold
115
+ if similarity >= 0.60 or line in remove_html_tags(sentence): # 80% similarity threshold
116
116
  line_time = clip_time
117
117
  next_line = prev_clip_time
118
118
  break
@@ -123,6 +123,35 @@ def get_line_timing(last_note):
123
123
  return line_time, next_line
124
124
 
125
125
 
126
- def get_last_two_sentences():
126
+ def get_last_two_sentences(last_note):
127
+ def similar(a, b):
128
+ return SequenceMatcher(None, a, b).ratio()
127
129
  lines = list(line_history.items())
128
- return lines[-1][0] if lines else '', lines[-2][0] if len(lines) > 1 else ''
130
+
131
+ if not last_note:
132
+ return lines[-1][0] if lines else '', lines[-2][0] if len(lines) > 1 else ''
133
+
134
+ current_line = ""
135
+ prev_line = ""
136
+
137
+ sentence = last_note['fields'][get_config().anki.sentence_field]['value']
138
+ if sentence:
139
+ found = False
140
+ for i, (line, clip_time) in enumerate(reversed(lines)):
141
+ similarity = similar(remove_html_tags(sentence), line)
142
+ logger.debug(f"Comparing: {remove_html_tags(sentence)} with {line} - Similarity: {similarity}")
143
+ if found:
144
+ prev_line = line
145
+ break
146
+ if similarity >= 0.60 or line in remove_html_tags(sentence): # 80% similarity threshold
147
+ found = True
148
+ current_line = line
149
+
150
+ logger.debug(f"Current Line: {current_line}")
151
+ logger.debug(f"Previous Line: {prev_line}")
152
+
153
+ if not current_line or not prev_line:
154
+ logger.debug("Couldn't find lines in history, using last two lines")
155
+ return lines[-1][0] if lines else '', lines[-2][0] if len(lines) > 1 else ''
156
+
157
+ return current_line, prev_line
GameSentenceMiner/gsm.py CHANGED
@@ -29,7 +29,7 @@ from GameSentenceMiner.util import *
29
29
  if is_windows():
30
30
  import win32api
31
31
 
32
- obs_process: Popen
32
+ obs_process: Popen = None
33
33
  procs_to_close = []
34
34
  settings_window: config_gui.ConfigApp = None
35
35
  obs_paused = False
@@ -89,22 +89,19 @@ class VideoToAudioHandler(FileSystemEventHandler):
89
89
  should_update_audio = False
90
90
  vad_trimmed_audio = ""
91
91
  logger.info("No SentenceAudio Field in config, skipping audio processing!")
92
- try:
93
92
  # Only update sentenceaudio if it's not present. Want to avoid accidentally overwriting sentence audio
94
- try:
95
- if get_config().anki.update_anki and last_note:
96
- anki.update_anki_card(last_note, note, audio_path=final_audio_output, video_path=video_path,
97
- tango=tango,
98
- should_update_audio=should_update_audio,
99
- ss_time=ss_timing)
100
- elif get_config().features.notify_on_update and should_update_audio:
101
- notification.send_audio_generated_notification(vad_trimmed_audio)
102
- except Exception as e:
103
- logger.error(f"Card failed to update! Maybe it was removed? {e}")
104
- except FileNotFoundError as f:
105
- logger.error("Something went wrong with processing, anki card not updated")
93
+ try:
94
+ if get_config().anki.update_anki and last_note:
95
+ anki.update_anki_card(last_note, note, audio_path=final_audio_output, video_path=video_path,
96
+ tango=tango,
97
+ should_update_audio=should_update_audio,
98
+ ss_time=ss_timing)
99
+ elif get_config().features.notify_on_update and should_update_audio:
100
+ notification.send_audio_generated_notification(vad_trimmed_audio)
101
+ except Exception as e:
102
+ logger.exception(f"Card failed to update! Maybe it was removed? {e}")
106
103
  except Exception as e:
107
- logger.error(f"Some error was hit catching to allow further work to be done: {e}", exc_info=1)
104
+ logger.exception(f"Some error was hit catching to allow further work to be done: {e}")
108
105
  if get_config().paths.remove_video and os.path.exists(video_path):
109
106
  os.remove(video_path) # Optionally remove the video after conversion
110
107
  if get_config().paths.remove_audio and os.path.exists(vad_trimmed_audio):
@@ -320,10 +317,11 @@ def close_obs():
320
317
 
321
318
  def restart_obs():
322
319
  global obs_process
323
- close_obs()
324
- time.sleep(2)
325
- obs_process = obs.start_obs()
326
- obs.connect_to_obs(start_replay=True)
320
+ if obs_process:
321
+ close_obs()
322
+ time.sleep(2)
323
+ obs_process = obs.start_obs()
324
+ obs.connect_to_obs(start_replay=True)
327
325
 
328
326
  def cleanup():
329
327
  logger.info("Performing cleanup...")
@@ -393,6 +391,7 @@ def main(reloading=False, do_config_input=True):
393
391
  if get_config().general.open_config_on_startup:
394
392
  settings_window.window.after(0, settings_window.show)
395
393
  settings_window.add_save_hook(update_icon)
394
+ settings_window.on_exit = exit_program
396
395
  settings_window.window.mainloop()
397
396
  except KeyboardInterrupt:
398
397
  cleanup()
@@ -39,11 +39,3 @@ def check_for_updates(force=False):
39
39
  return False, latest_version
40
40
  except Exception as e:
41
41
  logger.error(f"Error checking for updates: {e}")
42
-
43
- def update():
44
- try:
45
- pyperclip.copy("pip install --upgrade GameSentenceMiner")
46
- exit()
47
- except Exception as e:
48
- logger.error(f"Error updating {PACKAGE_NAME}: {e}")
49
- return False
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: GameSentenceMiner
3
- Version: 2.2.2.post2
4
- Summary: A tool for mining sentences from games. Update: Use ffprobe from GSM Directory
3
+ Version: 2.2.4
4
+ Summary: A tool for mining sentences from games. Update: Fix Previous Sentence When Mining from History
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
7
7
  Project-URL: Homepage, https://github.com/bpwhelan/GameSentenceMiner
@@ -1,14 +1,14 @@
1
1
  GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- GameSentenceMiner/anki.py,sha256=_yaHQZwOYooQssfJ5hbST5cC6vsffkSEvUIeMouwQZw,9208
3
- GameSentenceMiner/config_gui.py,sha256=d9bQUUI-QR879FJJsROcQ4Y7gk08h95uPNGN1DWdIuU,49005
4
- GameSentenceMiner/configuration.py,sha256=Cw5vUF74ZKcSinbciNMiLKpMO8M6sf-0THokHO_31nE,14010
2
+ GameSentenceMiner/anki.py,sha256=urgly10zM7etTXfagK327TKWXVq146jqkpTmewoim7s,9238
3
+ GameSentenceMiner/config_gui.py,sha256=EBl5TuzyqXUovq4YF-UQsl4W7DAzIpdzANI52AiTyoU,49743
4
+ GameSentenceMiner/configuration.py,sha256=Wd4Cozdus_Tl33_Qz4twibBx6p_3_mHMzdZfZ-B1qI4,14124
5
5
  GameSentenceMiner/ffmpeg.py,sha256=txTpco-IGWtfF8vIiWUzrtgI5TA1xPVIK-WJWxU02mM,10878
6
- GameSentenceMiner/gametext.py,sha256=pAovclbBSLigoyJMcdhNrieFDDPLJY3htHBGhjQ2Xk0,4081
7
- GameSentenceMiner/gsm.py,sha256=6LX3kFhyB1QoXFr5jzGZvONzQa6_PmPn_R7o2AiRRqA,16493
6
+ GameSentenceMiner/gametext.py,sha256=QQbZnV1eZ1DxwJl9fwfn8p6z1UjpSk6JRpxKmJ4CrUw,5210
7
+ GameSentenceMiner/gsm.py,sha256=qDa8Q8bjBNnmVGLDqiEYLTC_ZyBkS3zw2SmP4Tc_h0o,16375
8
8
  GameSentenceMiner/model.py,sha256=oh8VVT8T1UKekbmP6MGNgQ8jIuQ_7Rg4GPzDCn2kJo8,1999
9
9
  GameSentenceMiner/notification.py,sha256=WBaQWoPNhW4XqdPBUmxPBgjk0ngzH_4v9zMQ-XQAKC8,2010
10
10
  GameSentenceMiner/obs.py,sha256=3Flcjxy812VpF78EPI7sxlGx6yyM3GfqzlinW17SK20,6231
11
- GameSentenceMiner/package_updater.py,sha256=KBJwLrlcAyoGHNNmDSVdPgWawqfWiIWOodcZhYheoms,1486
11
+ GameSentenceMiner/package_updater.py,sha256=0uaLAp0WrWqostNTBWRS0laITjI9aN9Yt_6GXosS4NQ,1278
12
12
  GameSentenceMiner/util.py,sha256=cgKpPfRpouWI6tjE_35MWp8nXqRzXs3LvsYXWm5_DOg,4584
13
13
  GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
14
14
  GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -17,8 +17,8 @@ GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
17
17
  GameSentenceMiner/vad/silero_trim.py,sha256=syDJX_KbFmdyFFtnQqYTD0tICsUCJizYhs-atPgXtxA,1549
18
18
  GameSentenceMiner/vad/vosk_helper.py,sha256=-AAwK0cgOC5rK3_gL0sQgrPJ75E49g_PxZR4d5ckwc4,5826
19
19
  GameSentenceMiner/vad/whisper_helper.py,sha256=bpR1HVnJRn9H5u8XaHBqBJ6JwIjzqn-Fajps8QmQ4zc,3411
20
- GameSentenceMiner-2.2.2.post2.dist-info/METADATA,sha256=soTcs3hdtc4XGqR1wsuLUV4fPwVEBrzCCW8gy97pcn8,10131
21
- GameSentenceMiner-2.2.2.post2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
- GameSentenceMiner-2.2.2.post2.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
23
- GameSentenceMiner-2.2.2.post2.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
24
- GameSentenceMiner-2.2.2.post2.dist-info/RECORD,,
20
+ GameSentenceMiner-2.2.4.dist-info/METADATA,sha256=-S903oxc3YHCUd7s_F97f0CARKRJgk3E-yZ5AZ2u8pQ,10141
21
+ GameSentenceMiner-2.2.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
+ GameSentenceMiner-2.2.4.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
23
+ GameSentenceMiner-2.2.4.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
24
+ GameSentenceMiner-2.2.4.dist-info/RECORD,,