GameSentenceMiner 2.19.1__py3-none-any.whl → 2.19.3__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
@@ -559,10 +559,10 @@ def update_new_card():
559
559
  else:
560
560
  logger.info("New card(s) detected! Added to Processing Queue!")
561
561
  gsm_state.last_mined_line = game_line
562
- queue_card_for_processing(last_card, lines)
562
+ queue_card_for_processing(last_card, lines, game_line)
563
563
 
564
- def queue_card_for_processing(last_card, lines):
565
- card_queue.append((last_card, datetime.now(), lines))
564
+ def queue_card_for_processing(last_card, lines, last_mined_line):
565
+ card_queue.append((last_card, datetime.now(), lines, last_mined_line))
566
566
  texthooking_page.reset_checked_lines()
567
567
  try:
568
568
  obs.save_replay_buffer()
@@ -260,7 +260,7 @@ async def add_line_to_text_log(line, line_time=None):
260
260
  await add_event_to_texthooker(get_text_log()[-1])
261
261
  if get_config().overlay.websocket_port and overlay_server_thread.has_clients():
262
262
  if get_overlay_processor().ready:
263
- await get_overlay_processor().find_box_and_send_to_overlay(current_line_after_regex)
263
+ asyncio.create_task(get_overlay_processor().find_box_and_send_to_overlay(current_line_after_regex))
264
264
  add_srt_line(line_time, new_line)
265
265
  if 'nostatspls' not in new_line.scene.lower():
266
266
  GameLinesTable.add_line(new_line)
GameSentenceMiner/gsm.py CHANGED
@@ -187,7 +187,7 @@ class VideoToAudioHandler(FileSystemEventHandler):
187
187
  return
188
188
  try:
189
189
  if anki.card_queue and len(anki.card_queue) > 0:
190
- last_note, anki_card_creation_time, selected_lines = anki.card_queue.pop(
190
+ last_note, anki_card_creation_time, selected_lines, mined_line = anki.card_queue.pop(
191
191
  0)
192
192
  else:
193
193
  logger.info(
@@ -211,11 +211,11 @@ class VideoToAudioHandler(FileSystemEventHandler):
211
211
  full_text = ''
212
212
  if selected_lines:
213
213
  start_line = selected_lines[0]
214
- mined_line = get_mined_line(last_note, selected_lines)
214
+ # mined_line = get_mined_line(last_note, selected_lines)
215
215
  line_cutoff = selected_lines[-1].get_next_time()
216
216
  full_text = remove_html_and_cloze_tags(note['fields'][get_config().anki.sentence_field])
217
217
  else:
218
- mined_line = get_text_event(last_note)
218
+ # mined_line = get_text_event(last_note)
219
219
  if mined_line:
220
220
  start_line = mined_line
221
221
  if mined_line.next:
@@ -597,6 +597,16 @@
597
597
  "label": "Capture Interval (Seconds):",
598
598
  "tooltip": "Interval in seconds for periodic screen capture."
599
599
  }
600
+ ,
601
+ "periodic_ratio": {
602
+ "label": "Periodic Match Ratio:",
603
+ "tooltip": "Ratio (0-1) used during periodic scanning to determine how much of the region must match to count as detected. Higher = Less Strict, more Scanning."
604
+ }
605
+ ,
606
+ "number_of_local_scans_per_event": {
607
+ "label": "Local Scans Per Text Event:",
608
+ "tooltip": "How many local scans to perform per text event (agent, textractor, etc.) before stopping or sending results to the OCR engine. .1s delay between scans for now."
609
+ }
600
610
  },
601
611
  "wip": {
602
612
  "title": "WIP",
@@ -596,6 +596,16 @@
596
596
  "label": "キャプチャ間隔(秒):",
597
597
  "tooltip": "定期的な画面キャプチャの間隔(秒単位)。"
598
598
  }
599
+ ,
600
+ "periodic_ratio": {
601
+ "label": "定期一致比率:",
602
+ "tooltip": "定期スキャン中に使用される比率 (0-1)。領域がどれだけ一致すれば検出と見なすかを決定します。"
603
+ }
604
+ ,
605
+ "number_of_local_scans_per_event": {
606
+ "label": "イベントごとのローカルスキャン数:",
607
+ "tooltip": "停止するかOCRエンジンに送信する前に、イベントごとに実行するローカルスキャンの回数。"
608
+ }
599
609
  },
600
610
  "wip": {
601
611
  "title": "WIP",
@@ -585,6 +585,16 @@
585
585
  "label": "捕获间隔(秒):",
586
586
  "tooltip": "定期屏幕捕获的时间间隔(秒)。"
587
587
  }
588
+ ,
589
+ "periodic_ratio": {
590
+ "label": "定期匹配比率:",
591
+ "tooltip": "在定期扫描期间使用的比率(0-1),用于确定区域匹配多少才算检测到。"
592
+ }
593
+ ,
594
+ "number_of_local_scans_per_event": {
595
+ "label": "每次事件本地扫描数:",
596
+ "tooltip": "在停止或将结果发送到OCR引擎之前,每个事件执行的本地扫描次数。"
597
+ }
588
598
  },
589
599
  "wip": {
590
600
  "title": "WIP",
@@ -512,9 +512,11 @@ class ConfigApp:
512
512
  self.overlay_websocket_send_value = tk.BooleanVar(value=self.settings.overlay.monitor_to_capture)
513
513
  self.overlay_engine_value = tk.StringVar(value=self.settings.overlay.engine)
514
514
  self.periodic_value = tk.BooleanVar(value=self.settings.overlay.periodic)
515
+ self.periodic_ratio_value = tk.StringVar(value=str(self.settings.overlay.periodic_ratio))
515
516
  self.periodic_interval_value = tk.StringVar(value=str(self.settings.overlay.periodic_interval))
516
517
  self.scan_delay_value = tk.StringVar(value=str(self.settings.overlay.scan_delay))
517
518
  self.overlay_minimum_character_size_value = tk.StringVar(value=str(self.settings.overlay.minimum_character_size))
519
+ self.number_of_local_scans_per_event_value = tk.StringVar(value=str(getattr(self.settings.overlay, 'number_of_local_scans_per_event', 1)))
518
520
 
519
521
  # Master Config Settings
520
522
  self.switch_to_default_if_not_found_value = tk.BooleanVar(value=self.master_config.switch_to_default_if_not_found)
@@ -616,6 +618,28 @@ class ConfigApp:
616
618
  self.sync_changes_checkbutton.state(['!selected'])
617
619
 
618
620
  # Create a new Config instance
621
+ # Validate and clamp periodic_ratio to [0.0, 1.0]
622
+ try:
623
+ _periodic_ratio = float(self.periodic_ratio_value.get())
624
+ except Exception:
625
+ _periodic_ratio = 0.9
626
+ # clamp
627
+ if _periodic_ratio < 0.0:
628
+ _periodic_ratio = 0.0
629
+ if _periodic_ratio > 1.0:
630
+ _periodic_ratio = 1.0
631
+ # reflect back to UI variable (keep consistent formatting)
632
+ self.periodic_ratio_value.set(str(_periodic_ratio))
633
+
634
+ # Validate and clamp number_of_local_scans_per_event to positive integer
635
+ try:
636
+ _local_scans = int(float(self.number_of_local_scans_per_event_value.get()))
637
+ except Exception:
638
+ _local_scans = int(getattr(self.settings.overlay, 'number_of_local_scans_per_event', 1))
639
+ if _local_scans < 1:
640
+ _local_scans = 1
641
+ self.number_of_local_scans_per_event_value.set(str(_local_scans))
642
+
619
643
  config = ProfileConfig(
620
644
  scenes=self.settings.scenes,
621
645
  general=General(
@@ -754,7 +778,9 @@ class ConfigApp:
754
778
  engine=OverlayEngine(self.overlay_engine_value.get()).value if self.overlay_engine_value.get() else OverlayEngine.LENS.value,
755
779
  scan_delay=float(self.scan_delay_value.get()),
756
780
  periodic=float(self.periodic_value.get()),
781
+ periodic_ratio=_periodic_ratio,
757
782
  periodic_interval=float(self.periodic_interval_value.get()),
783
+ number_of_local_scans_per_event=int(self.number_of_local_scans_per_event_value.get()),
758
784
  minimum_character_size=int(self.overlay_minimum_character_size_value.get()),
759
785
  )
760
786
  # wip=WIP(
@@ -819,6 +845,14 @@ class ConfigApp:
819
845
 
820
846
  title_template = self.i18n.get('app', {}).get('title_with_profile', 'GameSentenceMiner Configuration - {profile_name}')
821
847
  self.window.title(title_template.format(profile_name=current_config.name))
848
+
849
+ try:
850
+ import mss as mss
851
+ self.monitors = [f"Monitor {i}: width: {monitor['width']}, height: {monitor['height']}" for i, monitor in enumerate(mss.mss().monitors[1:], start=1)]
852
+ if len(self.monitors) == 0:
853
+ self.monitors = [1]
854
+ except ImportError:
855
+ self.monitors = []
822
856
 
823
857
  if current_config.name != self.settings.name or self.settings.config_changed(current_config) or force_refresh:
824
858
  logger.info("Config changed, reloading settings.")
@@ -2434,6 +2468,22 @@ class ConfigApp:
2434
2468
  ttk.Entry(overlay_frame, textvariable=self.periodic_interval_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2435
2469
  self.current_row += 1
2436
2470
 
2471
+ # Periodic Ratio (how much of the screen must match to count)
2472
+ periodic_ratio_i18n = overlay_i18n.get('periodic_ratio', {})
2473
+ HoverInfoLabelWidget(overlay_frame, text=periodic_ratio_i18n.get('label', 'Periodic Ratio:'),
2474
+ tooltip=periodic_ratio_i18n.get('tooltip', 'Ratio (0-1) used during periodic scanning to determine matching threshold.'),
2475
+ row=self.current_row, column=0)
2476
+ ttk.Entry(overlay_frame, textvariable=self.periodic_ratio_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2477
+ self.current_row += 1
2478
+
2479
+ # Number of Local Scans Per Event
2480
+ local_scans_i18n = overlay_i18n.get('number_of_local_scans_per_event', {})
2481
+ HoverInfoLabelWidget(overlay_frame, text=local_scans_i18n.get('label', 'Local Scans Per Event:'),
2482
+ tooltip=local_scans_i18n.get('tooltip', 'How many local scans to perform per event before stopping or sending to lens.'),
2483
+ row=self.current_row, column=0)
2484
+ ttk.Entry(overlay_frame, textvariable=self.number_of_local_scans_per_event_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2485
+ self.current_row += 1
2486
+
2437
2487
  # Minimum Character Size
2438
2488
  minimum_character_size_i18n = overlay_i18n.get('minimum_character_size', {})
2439
2489
  HoverInfoLabelWidget(overlay_frame, text=minimum_character_size_i18n.get('label', 'Minimum Character Size:'),
@@ -675,8 +675,10 @@ class Overlay:
675
675
  monitor_to_capture: int = 0
676
676
  periodic: bool = False
677
677
  periodic_interval: float = 1.0
678
+ periodic_ratio: float = 0.9
678
679
  scan_delay: float = 0.25
679
680
  minimum_character_size: int = 0
681
+ number_of_local_scans_per_event: int = 1
680
682
 
681
683
  def __post_init__(self):
682
684
  if self.monitor_to_capture == -1:
@@ -330,56 +330,64 @@ class OverlayProcessor:
330
330
  # Check for cancellation after screenshot
331
331
  if asyncio.current_task().cancelled():
332
332
  raise asyncio.CancelledError()
333
-
333
+
334
334
  if self.oneocr:
335
- # 2. Use OneOCR to find general text areas (fast)
336
- res, text, oneocr_results, crop_coords_list = self.oneocr(
337
- full_screenshot,
338
- return_coords=True,
339
- multiple_crop_coords=True,
340
- return_one_box=False,
341
- furigana_filter_sensitivity=get_overlay_config().minimum_character_size,
342
- )
343
-
344
- if not crop_coords_list:
345
- return
346
-
347
- # Check for cancellation after OneOCR
348
- if asyncio.current_task().cancelled():
349
- raise asyncio.CancelledError()
350
-
351
- text_str = "".join([text for text in text if self.regex.match(text)])
352
-
353
- # RapidFuzz fuzzy match 90% to not send the same results repeatedly
354
- if self.last_oneocr_result and check_against_last:
335
+ tries = get_overlay_config().number_of_local_scans_per_event if not check_against_last else 1
336
+ for i in range(tries):
337
+ if i > 0:
338
+ try:
339
+ await asyncio.sleep(0.1)
340
+ except asyncio.CancelledError:
341
+ logger.info("OCR task cancelled during local scan delay")
342
+ raise
343
+ # 2. Use OneOCR to find general text areas (fast)
344
+ res, text, oneocr_results, crop_coords_list = self.oneocr(
345
+ full_screenshot,
346
+ return_coords=True,
347
+ multiple_crop_coords=True,
348
+ return_one_box=False,
349
+ furigana_filter_sensitivity=get_overlay_config().minimum_character_size,
350
+ )
351
+
352
+ if not crop_coords_list:
353
+ return
354
+
355
+ # Check for cancellation after OneOCR
356
+ if asyncio.current_task().cancelled():
357
+ raise asyncio.CancelledError()
355
358
 
356
- score = fuzz.ratio(text_str, self.last_oneocr_result)
357
- if score >= 80:
359
+ text_str = "".join([text for text in text if self.regex.match(text)])
360
+
361
+ # RapidFuzz fuzzy match 90% to not send the same results repeatedly
362
+ if self.last_oneocr_result and check_against_last:
363
+
364
+ score = fuzz.ratio(text_str, self.last_oneocr_result)
365
+ if score >= get_config().overlay.periodic_ratio * 100:
366
+ return
367
+ self.last_oneocr_result = text_str
368
+
369
+ await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
370
+
371
+ # If User Home is beangate
372
+ if is_beangate:
373
+ with open("oneocr_results.json", "w", encoding="utf-8") as f:
374
+ f.write(json.dumps(oneocr_results, ensure_ascii=False, indent=2))
375
+
376
+ if get_config().overlay.engine == OverlayEngine.ONEOCR.value and self.oneocr:
377
+ logger.info("Sent %d text boxes to overlay.", len(oneocr_results))
358
378
  return
359
- self.last_oneocr_result = text_str
360
379
 
361
- await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
362
-
363
- # If User Home is beangate
364
- if is_beangate:
365
- with open("oneocr_results.json", "w", encoding="utf-8") as f:
366
- f.write(json.dumps(oneocr_results, ensure_ascii=False, indent=2))
367
-
368
- if get_config().overlay.engine == OverlayEngine.ONEOCR.value and self.oneocr:
369
- logger.info("Sent %d text boxes to overlay.", len(oneocr_results))
370
- return
380
+ # Check for cancellation before creating composite image
381
+ if asyncio.current_task().cancelled():
382
+ raise asyncio.CancelledError()
371
383
 
372
- # Check for cancellation before creating composite image
373
- if asyncio.current_task().cancelled():
374
- raise asyncio.CancelledError()
375
-
376
- # 3. Create a composite image with only the detected text regions
377
- composite_image = self._create_composite_image(
378
- full_screenshot,
379
- crop_coords_list,
380
- monitor_width,
381
- monitor_height
382
- )
384
+ # 3. Create a composite image with only the detected text regions
385
+ composite_image = self._create_composite_image(
386
+ full_screenshot,
387
+ crop_coords_list,
388
+ monitor_width,
389
+ monitor_height
390
+ )
383
391
  else:
384
392
  composite_image = full_screenshot
385
393
 
@@ -408,7 +416,7 @@ class OverlayProcessor:
408
416
  # RapidFuzz fuzzy match 90% to not send the same results repeatedly
409
417
  if self.last_lens_result and check_against_last:
410
418
  score = fuzz.ratio(text_str, self.last_lens_result)
411
- if score >= 80:
419
+ if score >= get_config().overlay.periodic_ratio * 100:
412
420
  logger.info("Google Lens results are similar to the last results (score: %d). Skipping overlay update.", score)
413
421
  return
414
422
  self.last_lens_result = text_str
@@ -146,25 +146,27 @@ def get_matching_line(last_note: AnkiCard, lines=None) -> GameLine:
146
146
 
147
147
  if not lines:
148
148
  raise Exception("No voicelines in GSM. GSM can only do work on text that has been sent to it since it started. If you are not getting any text into GSM, please check your setup/config.")
149
+
150
+ last_line = lines[-1] # Store reference to the latest line
149
151
 
150
152
  if not last_note:
151
- return lines[-1]
153
+ return last_line
152
154
 
153
155
  sentence = last_note.get_field(get_config().anki.sentence_field)
154
156
  if not sentence:
155
- return lines[-1]
157
+ return last_line
156
158
 
157
159
  logger.info(f"Replay buffer length: {gsm_state.replay_buffer_length}")
158
160
  time_window = datetime.now() - timedelta(seconds=gsm_state.replay_buffer_length) - timedelta(seconds=5)
159
161
  for line in reversed(lines):
160
162
  if line.time < time_window:
161
163
  logger.info("Could not find matching sentence from GSM's history within the replay buffer time window. Using the latest line.")
162
- return lines[-1]
164
+ return last_line
163
165
  if lines_match(line.text, remove_html_and_cloze_tags(sentence)):
164
166
  return line
165
167
 
166
168
  logger.info("Could not find matching sentence from GSM's history. Using the latest line.")
167
- return lines[-1]
169
+ return last_line
168
170
 
169
171
 
170
172
  def get_text_event(last_note) -> GameLine:
@@ -235,14 +235,29 @@ def translate_line():
235
235
  if event_id is None:
236
236
  return jsonify({'error': 'Missing id'}), 400
237
237
 
238
+ prompt = f"""
239
+ **Professional Game Localization Task**
240
+
241
+ **Task Directive:**
242
+ Translate ONLY the provided line of game dialogue specified below into natural-sounding, context-aware {get_config().general.get_native_language_name()}. The translation must preserve the original tone and intent of the source.
243
+
244
+ **Output Requirements:**
245
+ - Provide only the single, best {get_config().general.get_native_language_name()} translation.
246
+ - Use expletives if they are natural for the context and enhance the translation's impact, but do not over-exaggerate.
247
+ - Do not include notes, alternatives, explanations, or any other surrounding text. Absolutely nothing but the translated line.
248
+
249
+ **Line to Translate:**
250
+ """
251
+
238
252
  if not get_config().ai.is_configured():
239
253
  return jsonify({'error': 'AI translation is not properly configured. Please check your settings in the "AI" Tab.'}), 400
240
254
  line = get_line_by_id(event_id)
241
255
  if line is None:
242
256
  return jsonify({'error': 'Invalid id'}), 400
243
257
  line_to_translate = text if text else line.text
244
- translation = get_ai_prompt_result(get_all_lines(), line_to_translate,
245
- line, get_current_game())
258
+ translation = get_ai_prompt_result(
259
+ get_all_lines(), line_to_translate, line, get_current_game(), custom_prompt=prompt
260
+ )
246
261
  line.set_TL(translation)
247
262
  return jsonify({'TL': translation}), 200
248
263
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.19.1
3
+ Version: 2.19.3
4
4
  Summary: A tool for mining sentences from games. Update: Dependencies, replay buffer based line searching, and bug fixes.
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -1,7 +1,7 @@
1
1
  GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- GameSentenceMiner/anki.py,sha256=9pjjJrQS7IbA6iTtOaJ0Hs2nBddYXTCZBF5lZ5I4dOs,29593
3
- GameSentenceMiner/gametext.py,sha256=U2uBXF6B8rYdXqYWaAfFxlZN-HXFcB-uryc2OMWau4I,13305
4
- GameSentenceMiner/gsm.py,sha256=Fqpy210vJIscxEaaX5bI4n-HEyp4EtkGSLkIreEs-Gw,34564
2
+ GameSentenceMiner/anki.py,sha256=jySFPzDYz0vItb12kwZ-rm9WmtxO8Kr41wK1JdwRnU4,29638
3
+ GameSentenceMiner/gametext.py,sha256=4PPm7QSWDmvsyooVjFANkd1Vnoy5ixbGRMHfYfhwGs0,13320
4
+ GameSentenceMiner/gsm.py,sha256=TpKJ2j2N_NgjT38p35nVVy5-Lvn4w49Spo4-a-6nfAc,34580
5
5
  GameSentenceMiner/obs.py,sha256=vhTFqGxHWEz9g-081gain6iI2poJM_D7v5vI8Kl7rqk,37918
6
6
  GameSentenceMiner/vad.py,sha256=iMSsoUZ7-aNoWKzDKfOHdB3Zk5U2hV7x5hqTny6rj08,21501
7
7
  GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -14,9 +14,9 @@ GameSentenceMiner/assets/icon32.png,sha256=Kww0hU_qke9_22wBuO_Nq0Dv2SfnOLwMhCyGg
14
14
  GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB_7W4sqs,192487
15
15
  GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
16
16
  GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
17
- GameSentenceMiner/locales/en_us.json,sha256=d2tObDFhZi8SZkIMbo5HfeXDo84tCpXbKXkhvzVKjyY,28166
18
- GameSentenceMiner/locales/ja_jp.json,sha256=Ok4VMPS-C57OC9nVtwWF_rKLNbxHkqvAz_S1G5c_Qt4,30236
19
- GameSentenceMiner/locales/zh_cn.json,sha256=NPoJqk_xayqp0dCfFdBx818-BtIXp6eni2Ql3G5Kon0,26165
17
+ GameSentenceMiner/locales/en_us.json,sha256=0NZRbq0zr-kCpKDAa2HJUhgOj2pmEIHgwGq-jgTcZ3s,28747
18
+ GameSentenceMiner/locales/ja_jp.json,sha256=huwh6rRAsJmQ5pUXr7gIG5EnpCsF-d_JvOhFg8KxiB8,30786
19
+ GameSentenceMiner/locales/zh_cn.json,sha256=soD29x8PefZ5M4t70nB61WeSkKdinP_ZbCLVb-toajw,26625
20
20
  GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=Ov04c-nKzh3sADxO-5JyZWVe4DlrHM9edM9tc7-97Jo,5970
22
22
  GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
@@ -37,21 +37,21 @@ GameSentenceMiner/tools/ss_selector.py,sha256=ob2oJdiYreDMMau7CvsglpnhZ1CDnJqop3
37
37
  GameSentenceMiner/tools/window_transparency.py,sha256=GtbxbmZg0-UYPXhfHff-7IKZyY2DKe4B9GdyovfmpeM,8166
38
38
  GameSentenceMiner/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  GameSentenceMiner/ui/anki_confirmation.py,sha256=krrT3q3anTtXNTPHz5ahXSd4genEnEvS07v1JYftBFg,15174
40
- GameSentenceMiner/ui/config_gui.py,sha256=OvwmTpg5zpTgX6TTgHwHQh2vGEgoses3H4a9BsQOxKk,155364
40
+ GameSentenceMiner/ui/config_gui.py,sha256=JHXlD6CE7o4YH1M85JSvGqc2-pNfuAyLgkztUn6ho1w,158268
41
41
  GameSentenceMiner/ui/furigana_filter_preview.py,sha256=DAT2-j6vSDHr9ufk6PiaLikEsbIp56B_OHIEeYLMwlk,17135
42
42
  GameSentenceMiner/ui/screenshot_selector.py,sha256=7QvDhOMpA0ej8x_lYtu6fhmrWbM1GCg-dps3XVWwk1Q,8234
43
43
  GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  GameSentenceMiner/util/audio_player.py,sha256=-yFsf0qoTSS1ga5rCmEJZJGUSJzXCvfZHY3t0NxycDk,7896
45
- GameSentenceMiner/util/configuration.py,sha256=5Ix2nrlTANpMS2AK7BBAJtA8UnFZgp8J8Rerll00GJo,47502
45
+ GameSentenceMiner/util/configuration.py,sha256=0E_LGBZL6K_P2oIHo-nI5OA6SPDk9SXdTf5ycF1-VeQ,47579
46
46
  GameSentenceMiner/util/db.py,sha256=iCHUzlgOJgNjQ5-oDa7gnDWmzdlEryOzbXfn9ToQPfY,33034
47
47
  GameSentenceMiner/util/electron_config.py,sha256=KfeJToeFFVw0IR5MKa-gBzpzaGrU-lyJbR9z-sDEHYU,8767
48
48
  GameSentenceMiner/util/ffmpeg.py,sha256=cAzztfY36Xf2WvsJDjavoiMOvA9ac2GVdCrSB4LzHk4,29007
49
49
  GameSentenceMiner/util/games_table.py,sha256=VM68MAsdyE6tpdwM4bDSk67qioBOvsEO8-TpnRmUnSo,12003
50
- GameSentenceMiner/util/get_overlay_coords.py,sha256=SfzSlrm0SjPe5BtkWZ0K3Z--7HNY_4sERTyrzSOaCls,25788
50
+ GameSentenceMiner/util/get_overlay_coords.py,sha256=jQ0hcrEh9CfvjlBRJez3Ly-er4MjBWC2zirA-hYz5hQ,26462
51
51
  GameSentenceMiner/util/gsm_utils.py,sha256=mASECTmN10c2yPL4NEfLg0Y0YWwFso1i6r_hhJPR3MY,10974
52
52
  GameSentenceMiner/util/model.py,sha256=R-_RYTYLSDNgBoVTPuPBcIHeOznIqi_vBzQ7VQ20WYk,6727
53
53
  GameSentenceMiner/util/notification.py,sha256=YBhf_mSo_i3cjBz-pmeTPx3wchKiG9BK2VBdZSa2prQ,4597
54
- GameSentenceMiner/util/text_log.py,sha256=nb4N6bId1hwVWSnKjbxl0kvTqBhJW2UL-xmwtyKmKrk,6835
54
+ GameSentenceMiner/util/text_log.py,sha256=6eekK0TTuh65YHDw6tjGFQUrCmV1P1ebNzkdxRNXP9k,6903
55
55
  GameSentenceMiner/util/communication/__init__.py,sha256=xh__yn2MhzXi9eLi89PeZWlJPn-cbBSjskhi1BRraXg,643
56
56
  GameSentenceMiner/util/communication/send.py,sha256=9tEpbodt1nqsA-XqyXZGMHK_80EJPnhMJJxvDF-w3Ug,578
57
57
  GameSentenceMiner/util/communication/websocket.py,sha256=RWPN9V6Gddqw1PmR_Ql8z0yjVihGvwSLSPQHXSxRlqM,3357
@@ -68,7 +68,7 @@ GameSentenceMiner/web/events.py,sha256=RJ8tIK8WUn7Fbgny23UJWrZ1SlhYzzT5p55E1uXRw
68
68
  GameSentenceMiner/web/gsm_websocket.py,sha256=B0VKpxmsRu0WRh5nFWlpDPBQ6-K2ed7TEIa0O6YWeoo,4166
69
69
  GameSentenceMiner/web/service.py,sha256=6cgUmDgtp3ZKzuPFszowjPoq-BDtC1bS3ux6sykeaqo,6662
70
70
  GameSentenceMiner/web/stats.py,sha256=LYMhekifcQo-cbfy2--b6vycKcu8RAoTnQA4TefcS6U,29037
71
- GameSentenceMiner/web/texthooking_page.py,sha256=xX2ZZpvTmXyBOKOkYZxKA3yNZQMbE930EEvUeY-xJpo,14332
71
+ GameSentenceMiner/web/texthooking_page.py,sha256=jnEBnxDj37BEbi1AGsiEk3GNOqBLsd9znIKC1OuO8jM,15068
72
72
  GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
74
74
  GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
@@ -135,9 +135,9 @@ GameSentenceMiner/web/templates/components/kanji_grid/thousand_character_classic
135
135
  GameSentenceMiner/web/templates/components/kanji_grid/wanikani_levels.json,sha256=8wjnnaYQqmho6t5tMxrIAc03512A2tYhQh5dfsQnfAM,11372
136
136
  GameSentenceMiner/web/templates/components/kanji_grid/words_hk_frequency_list.json,sha256=wRkqZNPzz6DT9OTPHpXwfqW96Qb96stCQNNgOL-ZdKk,17535
137
137
  GameSentenceMiner/wip/__init___.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
- gamesentenceminer-2.19.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
139
- gamesentenceminer-2.19.1.dist-info/METADATA,sha256=NefGHmCavrCJvSoBIVx-KUtdO36GWiCET6W3LWZvQmM,8121
140
- gamesentenceminer-2.19.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
141
- gamesentenceminer-2.19.1.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
142
- gamesentenceminer-2.19.1.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
143
- gamesentenceminer-2.19.1.dist-info/RECORD,,
138
+ gamesentenceminer-2.19.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
139
+ gamesentenceminer-2.19.3.dist-info/METADATA,sha256=5zf9Ize9DvAe4tUJt1S3P4kb0ghhgnX4wTxrTvZid-E,8121
140
+ gamesentenceminer-2.19.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
141
+ gamesentenceminer-2.19.3.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
142
+ gamesentenceminer-2.19.3.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
143
+ gamesentenceminer-2.19.3.dist-info/RECORD,,