GameSentenceMiner 2.8.14__py3-none-any.whl → 2.8.15__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.
@@ -157,8 +157,9 @@ class ConfigApp:
157
157
  custom_ffmpeg_settings=self.screenshot_custom_ffmpeg_settings.get(),
158
158
  screenshot_hotkey_updates_anki=self.screenshot_hotkey_update_anki.get(),
159
159
  seconds_after_line = self.seconds_after_line.get(),
160
- use_beginning_of_line_as_screenshot=self.use_beginning_of_line_as_screenshot.get(),
161
- use_new_screenshot_logic=self.use_new_screenshot_logic.get()
160
+ # use_beginning_of_line_as_screenshot=self.use_beginning_of_line_as_screenshot.get(),
161
+ # use_new_screenshot_logic=self.use_new_screenshot_logic.get(),
162
+ screenshot_timing_setting=self.screenshot_timing.get()
162
163
  ),
163
164
  audio=Audio(
164
165
  enabled=self.audio_enabled.get(),
@@ -199,7 +200,7 @@ class ConfigApp:
199
200
  advanced=Advanced(
200
201
  audio_player_path=self.audio_player_path.get(),
201
202
  video_player_path=self.video_player_path.get(),
202
- show_screenshot_buttons=self.show_screenshot_button.get(),
203
+ # show_screenshot_buttons=self.show_screenshot_button.get(),
203
204
  multi_line_line_break=self.multi_line_line_break.get(),
204
205
  multi_line_sentence_storage_field=self.multi_line_sentence_storage_field.get(),
205
206
  ocr_sends_to_clipboard=self.ocr_sends_to_clipboard.get(),
@@ -755,28 +756,46 @@ class ConfigApp:
755
756
  self.add_label_and_increment_row(screenshot_frame, "Custom FFmpeg options for re-encoding screenshots.",
756
757
  row=self.current_row, column=2)
757
758
 
759
+
758
760
  ttk.Label(screenshot_frame, text="Screenshot Hotkey Updates Anki:").grid(row=self.current_row, column=0, sticky='W')
759
761
  self.screenshot_hotkey_update_anki = tk.BooleanVar(value=self.settings.screenshot.screenshot_hotkey_updates_anki)
760
762
  ttk.Checkbutton(screenshot_frame, variable=self.screenshot_hotkey_update_anki).grid(row=self.current_row, column=1, sticky='W')
761
763
  self.add_label_and_increment_row(screenshot_frame, "Enable to allow Screenshot hotkey/button to update the latest anki card.", row=self.current_row,
762
764
  column=2)
763
765
 
764
- ttk.Label(screenshot_frame, text="Seconds After Line to SS:").grid(row=self.current_row, column=0, sticky='W')
766
+ ttk.Label(screenshot_frame, text="Screenshot Timing:").grid(row=self.current_row, column=0, sticky='W')
767
+ self.screenshot_timing = ttk.Combobox(screenshot_frame, values=['beginning', 'middle', 'end'])
768
+ self.screenshot_timing.insert(0, self.settings.screenshot.screenshot_timing_setting)
769
+ self.screenshot_timing.grid(row=self.current_row, column=1)
770
+ self.add_label_and_increment_row(screenshot_frame, "Select when to take the screenshot relative to the line: beginning, middle, or end.", row=self.current_row,
771
+ column=2)
772
+
773
+ ttk.Label(screenshot_frame, text="Screenshot Offset:").grid(row=self.current_row, column=0, sticky='W')
765
774
  self.seconds_after_line = ttk.Entry(screenshot_frame)
766
775
  self.seconds_after_line.insert(0, str(self.settings.screenshot.seconds_after_line))
767
776
  self.seconds_after_line.grid(row=self.current_row, column=1)
768
- self.add_label_and_increment_row(screenshot_frame, "This is only used for mining from lines from history (not current line)", row=self.current_row,
777
+ self.add_label_and_increment_row(screenshot_frame, "Time in seconds to offset the screenshot based on the Timing setting above (should almost always be positive)", row=self.current_row,
769
778
  column=2)
770
779
 
771
- ttk.Label(screenshot_frame, text="Use Beginning of Line as Screenshot:").grid(row=self.current_row, column=0, sticky='W')
772
- self.use_beginning_of_line_as_screenshot = tk.BooleanVar(value=self.settings.screenshot.use_beginning_of_line_as_screenshot)
773
- ttk.Checkbutton(screenshot_frame, variable=self.use_beginning_of_line_as_screenshot).grid(row=self.current_row, column=1, sticky='W')
774
- self.add_label_and_increment_row(screenshot_frame, "Enable to use the beginning of the line as the screenshot point. Adjust the above setting to fine-tine timing.", row=self.current_row, column=2)
775
-
776
- ttk.Label(screenshot_frame, text="Use alternative screenshot logic:").grid(row=self.current_row, column=0, sticky='W')
777
- self.use_new_screenshot_logic = tk.BooleanVar(value=self.settings.screenshot.use_new_screenshot_logic)
778
- ttk.Checkbutton(screenshot_frame, variable=self.use_new_screenshot_logic).grid(row=self.current_row, column=1, sticky='W')
779
- self.add_label_and_increment_row(screenshot_frame, "Enable to use the new screenshot logic. This will try to take the screenshot in the middle of the voiceline, or middle of the line if no audio/vad.", row=self.current_row, column=2)
780
+ # ttk.Label(screenshot_frame, text="Use Beginning of Line as Screenshot:").grid(row=self.current_row, column=0, sticky='W')
781
+ # self.use_beginning_of_line_as_screenshot = tk.BooleanVar(value=self.settings.screenshot.use_beginning_of_line_as_screenshot)
782
+ # ttk.Checkbutton(screenshot_frame, variable=self.use_beginning_of_line_as_screenshot).grid(row=self.current_row, column=1, sticky='W')
783
+ # self.add_label_and_increment_row(screenshot_frame, "Enable to use the beginning of the line as the screenshot point. Adjust the above setting to fine-tine timing.", row=self.current_row, column=2)
784
+ #
785
+ # ttk.Label(screenshot_frame, text="Use alternative screenshot logic:").grid(row=self.current_row, column=0, sticky='W')
786
+ # self.use_new_screenshot_logic = tk.BooleanVar(value=self.settings.screenshot.use_new_screenshot_logic)
787
+ # ttk.Checkbutton(screenshot_frame, variable=self.use_new_screenshot_logic).grid(row=self.current_row, column=1, sticky='W')
788
+ # self.add_label_and_increment_row(screenshot_frame, "Enable to use the new screenshot logic. This will try to take the screenshot in the middle of the voiceline, or middle of the line if no audio/vad.", row=self.current_row, column=2)
789
+ #
790
+
791
+ def update_audio_ffmpeg_settings(self, event):
792
+ selected_option = self.ffmpeg_preset_options.get()
793
+ if selected_option in self.ffmpeg_preset_options_map:
794
+ self.ffmpeg_reencode_options.delete(0, tk.END)
795
+ self.ffmpeg_reencode_options.insert(0, self.ffmpeg_preset_options_map[selected_option])
796
+ else:
797
+ self.ffmpeg_reencode_options.delete(0, tk.END)
798
+ self.ffmpeg_reencode_options.insert(0, "")
780
799
 
781
800
  @new_tab
782
801
  def create_audio_tab(self):
@@ -808,6 +827,28 @@ class ConfigApp:
808
827
  self.add_label_and_increment_row(audio_frame, "Offset in seconds to end audio processing.",
809
828
  row=self.current_row, column=2)
810
829
 
830
+ ttk.Label(audio_frame, text="FFmpeg Preset Options:").grid(row=self.current_row, column=0, sticky='W')
831
+
832
+ # Define display names and their corresponding values
833
+ self.ffmpeg_preset_options_map = {
834
+ "No Re-encode" : "",
835
+ "Simple loudness normalization (Simplest, Start Here)": "-c:a libopus -f opus -af \"loudnorm=I=-23:LRA=7:TP=-2\"",
836
+ "Downmix to mono with normalization (Recommended(?))": "-c:a libopus -ac 1 -f opus -application voip -apply_phase_inv 0 -af \"loudnorm=I=-23:dual_mono=true\"",
837
+ "Downmix to mono, 30kbps, normalized (Optimal(?))": "-c:a libopus -b:a 30k -ac 1 -f opus -application voip -apply_phase_inv 0 -af \"loudnorm=I=-23:dual_mono=true\"",
838
+
839
+ }
840
+
841
+ # Create a Combobox with display names
842
+ self.ffmpeg_preset_options = ttk.Combobox(audio_frame, values=list(self.ffmpeg_preset_options_map.keys()), width=50)
843
+ # self.ffmpeg_preset_options.set("Downmix to mono with normalization") # Set default display name
844
+ self.ffmpeg_preset_options.grid(row=self.current_row, column=1)
845
+
846
+ # Bind selection to update settings
847
+ self.ffmpeg_preset_options.bind("<<ComboboxSelected>>", self.update_audio_ffmpeg_settings)
848
+
849
+ self.add_label_and_increment_row(audio_frame, "Select a preset FFmpeg option for re-encoding screenshots.",
850
+ row=self.current_row, column=2)
851
+
811
852
  ttk.Label(audio_frame, text="FFmpeg Reencode Options:").grid(row=self.current_row, column=0, sticky='W')
812
853
  self.ffmpeg_reencode_options = ttk.Entry(audio_frame, width=50)
813
854
  self.ffmpeg_reencode_options.insert(0, self.settings.audio.ffmpeg_reencode_options)
@@ -815,6 +856,7 @@ class ConfigApp:
815
856
  self.add_label_and_increment_row(audio_frame, "Custom FFmpeg options for re-encoding audio files.",
816
857
  row=self.current_row, column=2)
817
858
 
859
+
818
860
  ttk.Label(audio_frame, text="Anki Media Collection:").grid(row=self.current_row, column=0, sticky='W')
819
861
  self.anki_media_collection = ttk.Entry(audio_frame)
820
862
  self.anki_media_collection.insert(0, self.settings.audio.anki_media_collection)
@@ -975,11 +1017,6 @@ class ConfigApp:
975
1017
  self.play_latest_audio_hotkey.grid(row=self.current_row, column=1)
976
1018
  self.add_label_and_increment_row(advanced_frame, "Hotkey to trim and play the latest audio.", row=self.current_row, column=2)
977
1019
 
978
- ttk.Label(advanced_frame, text="Show Screenshot Button:").grid(row=self.current_row, column=0, sticky='W')
979
- self.show_screenshot_button = tk.BooleanVar(value=self.settings.advanced.show_screenshot_buttons)
980
- ttk.Checkbutton(advanced_frame, variable=self.show_screenshot_button).grid(row=self.current_row, column=1, sticky='W')
981
- self.add_label_and_increment_row(advanced_frame, "Show the screenshot button in the utility gui.", row=self.current_row, column=2)
982
-
983
1020
  ttk.Label(advanced_frame, text="Multi-line Line-Break:").grid(row=self.current_row, column=0, sticky='W')
984
1021
  self.multi_line_line_break = ttk.Entry(advanced_frame)
985
1022
  self.multi_line_line_break.insert(0, self.settings.advanced.multi_line_line_break)
@@ -109,10 +109,21 @@ class Screenshot:
109
109
  quality: str = 85
110
110
  extension: str = "webp"
111
111
  custom_ffmpeg_settings: str = ''
112
+ custom_ffmpeg_option_selected: str = ''
112
113
  screenshot_hotkey_updates_anki: bool = False
113
114
  seconds_after_line: float = 1.0
114
115
  use_beginning_of_line_as_screenshot: bool = True
115
116
  use_new_screenshot_logic: bool = False
117
+ screenshot_timing_setting: str = '' # 'middle', 'end'
118
+
119
+ def __post_init__(self):
120
+ if not self.screenshot_timing_setting and self.use_beginning_of_line_as_screenshot:
121
+ self.screenshot_timing_setting = 'beginning'
122
+ if not self.screenshot_timing_setting and self.use_new_screenshot_logic:
123
+ self.screenshot_timing_setting = 'middle'
124
+ if not self.screenshot_timing_setting and not self.use_beginning_of_line_as_screenshot and not self.use_new_screenshot_logic:
125
+ self.screenshot_timing_setting = 'end'
126
+
116
127
 
117
128
 
118
129
  @dataclass_json
@@ -71,14 +71,27 @@ def get_screenshot_time(video_path, game_line, default_beginning=False, vad_begi
71
71
  if vad_beginning and vad_end and not doing_multi_line:
72
72
  logger.debug("Using VAD to determine screenshot time")
73
73
  screenshot_time_from_beginning = line_timestamp_in_video + vad_end - screenshot_offset
74
- elif get_config().screenshot.use_new_screenshot_logic:
74
+ elif get_config().screenshot.screenshot_timing_setting == "beginning":
75
+ logger.debug("Using beginning of line for screenshot")
76
+ screenshot_time_from_beginning = line_timestamp_in_video + screenshot_offset
77
+ elif get_config().screenshot.screenshot_timing_setting == "middle":
75
78
  if game_line.next:
76
79
  logger.debug("Finding time between lines for screenshot")
77
80
  screenshot_time_from_beginning = line_timestamp_in_video + ((game_line.next.time - game_line.time).total_seconds() / 2)
78
81
  else:
79
82
  logger.debug("Using end of line for screenshot")
80
83
  screenshot_time_from_beginning = file_length - screenshot_offset
84
+ elif get_config().screenshot.screenshot_timing_setting == "end":
85
+ logger.debug("Using end of line for screenshot")
86
+ if game_line.next:
87
+ logger.debug("Finding time between lines for screenshot")
88
+ screenshot_time_from_beginning = line_timestamp_in_video + (game_line.next.time - game_line.time).total_seconds() - screenshot_offset
89
+ else:
90
+ logger.debug("Using end of video for screenshot")
91
+ # If no next line, use the end of the video
92
+ screenshot_time_from_beginning = file_length - screenshot_offset
81
93
  else:
94
+ logger.error(f"Invalid screenshot timing setting: {get_config().screenshot.screenshot_timing_setting}")
82
95
  screenshot_time_from_beginning = line_timestamp_in_video + screenshot_offset
83
96
 
84
97
  # Check if the calculated time is out of bounds
@@ -78,13 +78,15 @@ async def listen_websocket():
78
78
  if e.response.status_code == 404:
79
79
  logger.info("Texthooker WebSocket connection failed. Attempting some fixes...")
80
80
  try_other = True
81
- if not (isinstance(e, ConnectionResetError) or isinstance(e, ConnectionError) or isinstance(e, InvalidStatus) or isinstance(e, websockets.ConnectionClosed)):
82
- logger.error(f"Unexpected error in Texthooker WebSocket connection: {e}")
83
- websocket_connected = False
84
- if not reconnecting:
85
- logger.warning(f"Texthooker WebSocket connection lost, Defaulting to clipboard if enabled. Attempting to Reconnect...")
86
- reconnecting = True
87
- await asyncio.sleep(5)
81
+ await asyncio.sleep(0.1)
82
+ else:
83
+ if not (isinstance(e, ConnectionResetError) or isinstance(e, ConnectionError) or isinstance(e, InvalidStatus) or isinstance(e, websockets.ConnectionClosed)):
84
+ logger.error(f"Unexpected error in Texthooker WebSocket connection: {e}")
85
+ websocket_connected = False
86
+ if not reconnecting:
87
+ logger.warning(f"Texthooker WebSocket connection lost, Defaulting to clipboard if enabled. Attempting to Reconnect...")
88
+ reconnecting = True
89
+ await asyncio.sleep(5)
88
90
 
89
91
  async def handle_new_text_event(current_clipboard, line_time=None):
90
92
  global current_line, current_line_time, current_line_after_regex
GameSentenceMiner/gsm.py CHANGED
@@ -294,8 +294,6 @@ def get_screenshot():
294
294
  encoded_image = ffmpeg.process_image(image)
295
295
  if get_config().anki.update_anki and get_config().screenshot.screenshot_hotkey_updates_anki:
296
296
  last_note = anki.get_last_anki_card()
297
- if last_note:
298
- logger.debug(json.dumps(last_note))
299
297
  if get_config().features.backfill_audio:
300
298
  last_note = anki.get_cards_by_sentence(gametext.current_line)
301
299
  if last_note:
@@ -308,7 +306,7 @@ def get_screenshot():
308
306
  else:
309
307
  notification.send_screenshot_saved(encoded_image)
310
308
  except Exception as e:
311
- logger.error(f"Failed to get Screenshot {e}")
309
+ logger.error(f"Failed to get Screenshot: {e}")
312
310
 
313
311
 
314
312
  def create_image():
@@ -335,7 +335,7 @@ def get_window(window_name):
335
335
  else:
336
336
  return None
337
337
  except Exception as e:
338
- print(f"Error finding window '{self.window_name}': {e}")
338
+ print(f"Error finding window '{window_name}': {e}")
339
339
  return None
340
340
 
341
341
  if __name__ == "__main__":
@@ -158,10 +158,11 @@
158
158
  }
159
159
  const events = await res.json();
160
160
 
161
+ let historyEvents = []
161
162
  events.forEach(ev => {
162
163
  if (!displayedEventIds.has(ev.id)) {
163
164
  if (ev.history) {
164
- addNewEventToHistory(ev)
165
+ historyEvents.push(ev);
165
166
  document.getElementById('initial-events-separator').style.display = 'block';
166
167
  } else {
167
168
  addNewEvent(ev)
@@ -177,6 +178,9 @@
177
178
  }
178
179
  }
179
180
  });
181
+ if (historyEvents.length > 0) {
182
+ addEventsToHistory(historyEvents);
183
+ }
180
184
  // checkboxes = Array.from(document.querySelectorAll('#session-events input[type="checkbox"]')); // Update checkboxes array after new events
181
185
  } catch (error) {
182
186
  console.error("Error fetching events:", error);
@@ -185,26 +189,30 @@
185
189
  }
186
190
  }
187
191
 
188
- function addNewEventToHistory(event) {
189
- displayedEventIds.add(event.id);
192
+ function addEventsToHistory(events) {
190
193
  const container = document.getElementById('initial-events');
191
- const div = document.createElement('div');
192
- // div.className = 'textline';
194
+ const fragment = document.createDocumentFragment();
193
195
 
194
- const shadowRoot = div.attachShadow({ mode: 'open' });
196
+ events.forEach(event => {
197
+ displayedEventIds.add(event.id);
198
+ const div = document.createElement('div');
199
+ const shadowRoot = div.attachShadow({ mode: 'open' });
195
200
 
196
- const wrapper = document.createElement('div');
197
- wrapper.className = 'textline';
198
- wrapper.innerHTML = `<p>${event.text}</p>
201
+ const wrapper = document.createElement('div');
202
+ wrapper.className = 'textline';
203
+ wrapper.innerHTML = `<p>${event.text}</p>
199
204
  <em class="clock-icon">${event.time.replace(' GMT', '')}</em>
200
205
  `;
201
206
 
202
- const style = document.createElement('style');
203
- style.textContent = mainStyle.innerHTML;
204
- shadowRoot.appendChild(style);
205
- shadowRoot.appendChild(wrapper);
207
+ const style = document.createElement('style');
208
+ style.textContent = mainStyle.innerHTML;
209
+ shadowRoot.appendChild(style);
210
+ shadowRoot.appendChild(wrapper);
206
211
 
207
- container.appendChild(div);
212
+ fragment.appendChild(div);
213
+ });
214
+
215
+ container.appendChild(fragment);
208
216
  window.scrollTo({
209
217
  top: document.documentElement.scrollHeight,
210
218
  });
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.8.14
3
+ Version: 2.8.15
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
@@ -1,11 +1,11 @@
1
1
  GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  GameSentenceMiner/anki.py,sha256=OCLgZa-iEp93v-R0zKFkDCjule_EAoP5rIqtnMHLnOw,14226
3
- GameSentenceMiner/config_gui.py,sha256=RHiiQxALMuVNg3ydNO49q7dtrYudGJIbLOXMk2NYoOs,71617
4
- GameSentenceMiner/configuration.py,sha256=jRuEgIM78W4rDrbAr8fABbNKeGlcS7P2JZP-Q1cBUV8,21922
3
+ GameSentenceMiner/config_gui.py,sha256=-xZRTzFtnhnmbSiL03XpNrzV29Pb891nLuXHI_CZw7I,73759
4
+ GameSentenceMiner/configuration.py,sha256=-De0KfXu0jHTPl0xyktUxT-_fNUS_AK7nmzblKXRdGc,22525
5
5
  GameSentenceMiner/electron_config.py,sha256=dGcPYCISPehXubYSzsDuI2Gl092MYK0u3bTnkL9Jh1Y,9787
6
- GameSentenceMiner/ffmpeg.py,sha256=MiraA1cYv0g5adwwI8f-zeFL0kG7sVuhxQSF_OuzhvU,13732
7
- GameSentenceMiner/gametext.py,sha256=ClSpOeohBWG17MRVIbhXfNDnkUdxU9mTspGv9975uEc,5422
8
- GameSentenceMiner/gsm.py,sha256=BiCxMJN9_BoX3NL0UkNAuoZk5OnrkQ7PSFgSCzrDJFc,25459
6
+ GameSentenceMiner/ffmpeg.py,sha256=lLZ9v8_h5wfenLC6W36Ikt0Q7HQrChxsZ6lPk2umXjI,14658
7
+ GameSentenceMiner/gametext.py,sha256=pyIjMxMgKAAIyKzvtq8FV-zdg1ETRf7GVgkE19_2-B4,5513
8
+ GameSentenceMiner/gsm.py,sha256=bwDt7yAM9_Jf0BY0oxs6vwL8jGrHxnw_sznqbJp5Hdg,25382
9
9
  GameSentenceMiner/model.py,sha256=JdnkT4VoPOXmOpRgFdvERZ09c9wLN6tUJxdrKlGZcqo,5305
10
10
  GameSentenceMiner/notification.py,sha256=FY39ChSRK0Y8TQ6lBGsLnpZUFPtFpSy2tweeXVoV7kc,2809
11
11
  GameSentenceMiner/obs.py,sha256=GPlsFrcv1eYelXyJfpspGK0iZK5AXPkoFsIGdB7eJrk,10002
@@ -25,7 +25,7 @@ GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
25
25
  GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=rQC6C8PKJXWoAvwCOYa363kodQQBwl1YNeYsD0bBbx4,1957
26
26
  GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
27
27
  GameSentenceMiner/ocr/owocr_area_selector.py,sha256=gwYOz-fA5qoL63wh77eyGJtBtO7YVvWyO5cHb3D0Oz4,46738
28
- GameSentenceMiner/ocr/owocr_helper.py,sha256=ZGAoekdkcqzluA1_QkjbsTM7D4LdW1ceW19msUwlG78,17388
28
+ GameSentenceMiner/ocr/owocr_helper.py,sha256=-ezF6AO7ayZBs2vMt0Zj7D-gc8YbrgO69mFsJD7VmRs,17383
29
29
  GameSentenceMiner/owocr/owocr/__init__.py,sha256=opjBOyGGyEqZCE6YdZPnyt7nVfiwyELHsXA0jAsjm14,25
30
30
  GameSentenceMiner/owocr/owocr/__main__.py,sha256=r8MI6RAmbkTWqOJ59uvXoDS7CSw5jX5war9ULGWELrA,128
31
31
  GameSentenceMiner/owocr/owocr/config.py,sha256=n-xtVylb2Q_H84jb1ZsIGxPQjTNnyvnRny1RhtaLJM8,7550
@@ -50,10 +50,10 @@ GameSentenceMiner/web/static/web-app-manifest-192x192.png,sha256=EfSNnBmsSaLfESb
50
50
  GameSentenceMiner/web/static/web-app-manifest-512x512.png,sha256=wyqgCWCrLEUxSRXmaA3iJEESd-vM-ZmlTtZFBY4V8Pk,230819
51
51
  GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
53
- GameSentenceMiner/web/templates/utility.html,sha256=y3HS4ShvmsBHtK5RkA2Unq77SWCvbwkcSxuXzTZV1H8,15976
54
- gamesentenceminer-2.8.14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
55
- gamesentenceminer-2.8.14.dist-info/METADATA,sha256=JSiTQV0z-Ko1VEI8hfp7Beo50mMIKOhohHU_fKRPUXY,5933
56
- gamesentenceminer-2.8.14.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
57
- gamesentenceminer-2.8.14.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
58
- gamesentenceminer-2.8.14.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
59
- gamesentenceminer-2.8.14.dist-info/RECORD,,
53
+ GameSentenceMiner/web/templates/utility.html,sha256=NUp4Yjs6_j7YeqsM2rcF0LzwS6nXSBUWJDl-k2E8BbM,16270
54
+ gamesentenceminer-2.8.15.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
55
+ gamesentenceminer-2.8.15.dist-info/METADATA,sha256=bLKHdjfoOke5LB1zD8IerMRtf_WvCAaAsSGtUxcg-Us,5933
56
+ gamesentenceminer-2.8.15.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
57
+ gamesentenceminer-2.8.15.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
58
+ gamesentenceminer-2.8.15.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
59
+ gamesentenceminer-2.8.15.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.1.0)
2
+ Generator: setuptools (80.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5