GameSentenceMiner 2.10.10__py3-none-any.whl → 2.10.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/gsm.py +7 -0
- GameSentenceMiner/ocr/owocr_area_selector.py +98 -15
- GameSentenceMiner/ocr/owocr_helper.py +2 -2
- GameSentenceMiner/util/configuration.py +1 -0
- GameSentenceMiner/web/service.py +10 -21
- GameSentenceMiner/web/texthooking_page.py +4 -4
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/RECORD +12 -12
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/top_level.txt +0 -0
GameSentenceMiner/gsm.py
CHANGED
@@ -452,6 +452,13 @@ def cleanup():
|
|
452
452
|
if icon:
|
453
453
|
icon.stop()
|
454
454
|
|
455
|
+
for video in gsm_state.videos_to_remove:
|
456
|
+
try:
|
457
|
+
if os.path.exists(video):
|
458
|
+
os.remove(video)
|
459
|
+
except Exception as e:
|
460
|
+
logger.error(f"Error removing temporary video file {video}: {e}")
|
461
|
+
|
455
462
|
settings_window.window.destroy()
|
456
463
|
time.sleep(5)
|
457
464
|
logger.info("Cleanup complete.")
|
@@ -20,6 +20,7 @@ except ImportError:
|
|
20
20
|
|
21
21
|
try:
|
22
22
|
import tkinter as tk
|
23
|
+
from tkinter import font as tkfont # NEW: Import for better font control
|
23
24
|
|
24
25
|
selector_available = True
|
25
26
|
except ImportError:
|
@@ -206,6 +207,66 @@ class ScreenSelector:
|
|
206
207
|
self.drawn_rect_ids.append(new_rect_id)
|
207
208
|
print("Redo: Restored rectangle.")
|
208
209
|
|
210
|
+
# --- NEW METHOD TO DISPLAY INSTRUCTIONS ---
|
211
|
+
def _create_instructions_widget(self, canvas):
|
212
|
+
"""Creates a text box with usage instructions on the canvas."""
|
213
|
+
instructions_text = (
|
214
|
+
"How to Use:\n"
|
215
|
+
" • Left Click + Drag: Create a capture area (green).\n"
|
216
|
+
" • Shift + Left Click + Drag: Create an exclusion area (orange).\n"
|
217
|
+
" • Right-Click on a box: Delete it.\n\n"
|
218
|
+
"Hotkeys:\n"
|
219
|
+
" • Ctrl + S: Save and Quit\n"
|
220
|
+
" • Ctrl + Z / Ctrl + Y: Undo / Redo\n"
|
221
|
+
" • M: Toggle background visibility\n"
|
222
|
+
" • I: Toggle these instructions\n"
|
223
|
+
" • Esc: Quit without saving"
|
224
|
+
" "
|
225
|
+
)
|
226
|
+
|
227
|
+
# Use a common, readable font
|
228
|
+
instruction_font = tkfont.Font(family="Segoe UI", size=10, weight="normal")
|
229
|
+
|
230
|
+
# Create the text item first to get its size
|
231
|
+
text_id = canvas.create_text(
|
232
|
+
20, 20, # Position with a small margin
|
233
|
+
text=instructions_text,
|
234
|
+
anchor=tk.NW,
|
235
|
+
fill='white',
|
236
|
+
font=instruction_font,
|
237
|
+
justify=tk.LEFT
|
238
|
+
)
|
239
|
+
|
240
|
+
# Get the bounding box of the text to draw a background
|
241
|
+
text_bbox = canvas.bbox(text_id)
|
242
|
+
|
243
|
+
# Create a background rectangle with padding
|
244
|
+
rect_id = canvas.create_rectangle(
|
245
|
+
text_bbox[0] - 10, # left
|
246
|
+
text_bbox[1] - 10, # top
|
247
|
+
text_bbox[2] + 10, # right
|
248
|
+
text_bbox[3] + 10, # bottom
|
249
|
+
fill='#2B2B2B', # Dark, semi-opaque background
|
250
|
+
outline='white',
|
251
|
+
width=1
|
252
|
+
)
|
253
|
+
|
254
|
+
# Lower the rectangle so it's behind the text
|
255
|
+
canvas.tag_lower(rect_id, text_id)
|
256
|
+
|
257
|
+
def toggle_instructions(self, event=None):
|
258
|
+
canvas = event.widget.winfo_toplevel().winfo_children()[0]
|
259
|
+
# Find all text and rectangle items (assuming only one of each for instructions)
|
260
|
+
text_items = [item for item in canvas.find_all() if canvas.type(item) == 'text']
|
261
|
+
rect_items = [item for item in canvas.find_all() if canvas.type(item) == 'rectangle']
|
262
|
+
|
263
|
+
if text_items and rect_items:
|
264
|
+
current_state = canvas.itemcget(text_items[0], 'state')
|
265
|
+
new_state = tk.NORMAL if current_state == tk.HIDDEN else tk.HIDDEN
|
266
|
+
for item in text_items + rect_items:
|
267
|
+
canvas.itemconfigure(item, state=new_state)
|
268
|
+
print("Toggled instructions visibility.")
|
269
|
+
|
209
270
|
def start(self):
|
210
271
|
self.root = tk.Tk()
|
211
272
|
self.root.withdraw()
|
@@ -230,6 +291,10 @@ class ScreenSelector:
|
|
230
291
|
canvas.pack(fill=tk.BOTH, expand=True)
|
231
292
|
canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)
|
232
293
|
|
294
|
+
# --- MODIFIED: CALL THE INSTRUCTION WIDGET CREATOR ---
|
295
|
+
self._create_instructions_widget(canvas)
|
296
|
+
# --- END MODIFICATION ---
|
297
|
+
|
233
298
|
# Draw existing rectangles (which were converted to absolute pixels on load)
|
234
299
|
for _, abs_coords, is_excluded in self.rectangles:
|
235
300
|
x_abs, y_abs, w_abs, h_abs = abs_coords
|
@@ -275,17 +340,37 @@ class ScreenSelector:
|
|
275
340
|
self.current_rect_id = self.start_x = self.start_y = None
|
276
341
|
|
277
342
|
def on_right_click(event):
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
343
|
+
# Iterate through our rectangles in reverse to find the topmost one.
|
344
|
+
for i in range(len(self.rectangles) - 1, -1, -1):
|
345
|
+
_monitor, abs_coords, _is_excluded = self.rectangles[i]
|
346
|
+
x_abs, y_abs, w_abs, h_abs = abs_coords
|
347
|
+
canvas_x1 = x_abs - self.bounding_box['left']
|
348
|
+
canvas_y1 = y_abs - self.bounding_box['top']
|
349
|
+
canvas_x2 = canvas_x1 + w_abs
|
350
|
+
canvas_y2 = canvas_y1 + h_abs
|
351
|
+
|
352
|
+
if canvas_x1 <= event.x <= canvas_x2 and canvas_y1 <= event.y <= canvas_y2:
|
353
|
+
# --- UNDO/REDO CHANGE ---
|
354
|
+
# We found the rectangle. Prepare the 'remove' action.
|
355
|
+
# We need to save the data AND its original index to restore it correctly.
|
356
|
+
rect_tuple_to_del = self.rectangles[i]
|
357
|
+
item_id_to_del = self.drawn_rect_ids[i]
|
358
|
+
|
359
|
+
self.redo_stack.append((*rect_tuple_to_del, i))
|
360
|
+
|
361
|
+
# Now, perform the deletion
|
362
|
+
del self.rectangles[i]
|
363
|
+
del self.drawn_rect_ids[i]
|
364
|
+
canvas.delete(item_id_to_del)
|
365
|
+
print("Deleted rectangle.")
|
366
|
+
|
367
|
+
break # Stop after deleting the topmost one
|
286
368
|
|
287
369
|
def toggle_image_mode(e=None):
|
288
|
-
self.image_mode = not self.image_mode
|
370
|
+
self.image_mode = not self.image_mode
|
371
|
+
# Only change alpha of the main window, not the text widget
|
372
|
+
window.attributes("-alpha", 1.0 if self.image_mode else 0.25)
|
373
|
+
print("Toggled background visibility.")
|
289
374
|
|
290
375
|
def on_enter(e=None):
|
291
376
|
canvas.focus_set()
|
@@ -296,13 +381,15 @@ class ScreenSelector:
|
|
296
381
|
canvas.bind('<ButtonRelease-1>', on_release)
|
297
382
|
canvas.bind('<Button-3>', on_right_click)
|
298
383
|
canvas.bind('<Control-s>', self.save_rects)
|
299
|
-
canvas.bind('<Control-z>', self.undo_last_rect)
|
300
384
|
canvas.bind('<Control-y>', self.redo_last_rect)
|
385
|
+
canvas.bind('<Control-z>', self.undo_last_rect)
|
301
386
|
canvas.bind("<Escape>", self.quit_app)
|
302
387
|
canvas.bind("<m>", toggle_image_mode)
|
388
|
+
canvas.bind("<i>", self.toggle_instructions)
|
303
389
|
|
304
390
|
canvas.focus_set()
|
305
|
-
|
391
|
+
# The print message is now redundant but kept for console feedback
|
392
|
+
print("Starting UI. See on-screen instructions. Press Esc to quit, Ctrl+S to save.")
|
306
393
|
self.root.mainloop()
|
307
394
|
|
308
395
|
def quit_app(self, event=None):
|
@@ -350,10 +437,6 @@ if __name__ == "__main__":
|
|
350
437
|
target_window_title = "Windowed Projector (Preview)" # Default
|
351
438
|
if len(sys.argv) > 1:
|
352
439
|
target_window_title = sys.argv[1]
|
353
|
-
# else:
|
354
|
-
# print("Usage: python your_script_name.py \"Target Window Title\"", file=sys.stderr)
|
355
|
-
# print("Example: python selector.py \"Windowed Projector (Preview)\"", file=sys.stderr)
|
356
|
-
# sys.exit(1)
|
357
440
|
|
358
441
|
selection_result = get_screen_selection(target_window_title)
|
359
442
|
|
@@ -241,12 +241,12 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
241
241
|
|
242
242
|
line_start_time = time if time else datetime.now()
|
243
243
|
|
244
|
-
if not twopassocr:
|
244
|
+
if manual or not twopassocr:
|
245
245
|
if previous_text and fuzz.ratio(orig_text_string, previous_orig_text) >= 90:
|
246
246
|
logger.info("Seems like Text we already sent, not doing anything.")
|
247
247
|
return
|
248
248
|
save_result_image(img)
|
249
|
-
asyncio.run(send_result(text,
|
249
|
+
asyncio.run(send_result(text, line_start_time))
|
250
250
|
previous_orig_text = orig_text_string
|
251
251
|
previous_text = None
|
252
252
|
previous_img = None
|
GameSentenceMiner/web/service.py
CHANGED
@@ -21,7 +21,7 @@ def handle_texthooker_button(video_path='', get_audio_from_video=None):
|
|
21
21
|
if get_config().advanced.audio_player_path:
|
22
22
|
play_audio_in_external(gsm_state.previous_audio)
|
23
23
|
elif get_config().advanced.video_player_path:
|
24
|
-
play_video_in_external(line,
|
24
|
+
play_video_in_external(line, video_path)
|
25
25
|
else:
|
26
26
|
import sounddevice as sd
|
27
27
|
data, samplerate = gsm_state.previous_audio
|
@@ -35,9 +35,7 @@ def handle_texthooker_button(video_path='', get_audio_from_video=None):
|
|
35
35
|
play_audio_in_external(audio)
|
36
36
|
gsm_state.previous_audio = audio
|
37
37
|
elif get_config().advanced.video_player_path:
|
38
|
-
|
39
|
-
gsm_state.previous_audio = new_video_path
|
40
|
-
gsm_state.previous_replay = new_video_path
|
38
|
+
play_video_in_external(line, video_path)
|
41
39
|
else:
|
42
40
|
import sounddevice as sd
|
43
41
|
import soundfile as sf
|
@@ -75,8 +73,8 @@ def handle_texthooker_button(video_path='', get_audio_from_video=None):
|
|
75
73
|
logger.debug(f"Error Playing Audio/Video: {e}", exc_info=True)
|
76
74
|
return
|
77
75
|
finally:
|
78
|
-
|
79
|
-
|
76
|
+
gsm_state.previous_replay = video_path
|
77
|
+
gsm_state.videos_to_remove.add(video_path)
|
80
78
|
|
81
79
|
|
82
80
|
def play_audio_in_external(filepath):
|
@@ -94,37 +92,28 @@ def play_audio_in_external(filepath):
|
|
94
92
|
|
95
93
|
|
96
94
|
def play_video_in_external(line, filepath):
|
97
|
-
def move_video_when_closed(p, fp):
|
98
|
-
p.wait()
|
99
|
-
os.remove(fp)
|
100
|
-
|
101
|
-
shutil.move(filepath, get_temporary_directory())
|
102
|
-
new_filepath = os.path.join(get_temporary_directory(), os.path.basename(filepath))
|
103
|
-
|
104
95
|
command = [get_config().advanced.video_player_path]
|
105
96
|
|
106
|
-
start, _, _, _ = get_video_timings(
|
97
|
+
start, _, _, _ = get_video_timings(filepath, line)
|
107
98
|
|
108
99
|
if start:
|
109
100
|
if "vlc" in get_config().advanced.video_player_path:
|
110
101
|
command.extend(["--start-time", convert_to_vlc_seconds(start), '--one-instance'])
|
111
102
|
else:
|
112
103
|
command.extend(["--start", convert_to_vlc_seconds(start)])
|
113
|
-
command.append(os.path.normpath(
|
104
|
+
command.append(os.path.normpath(filepath))
|
114
105
|
|
115
106
|
logger.info(" ".join(command))
|
116
107
|
|
117
108
|
|
118
109
|
|
119
110
|
try:
|
120
|
-
|
121
|
-
|
122
|
-
threading.Thread(target=move_video_when_closed, args=(proc, filepath)).start()
|
111
|
+
subprocess.Popen(command)
|
112
|
+
logger.info(f"Opened {filepath} in {get_config().advanced.video_player_path}.")
|
123
113
|
except FileNotFoundError:
|
124
|
-
|
114
|
+
logger.error("VLC not found. Make sure it's installed and in your PATH.")
|
125
115
|
except Exception as e:
|
126
|
-
|
127
|
-
return new_filepath
|
116
|
+
logger.error(f"An error occurred: {e}")
|
128
117
|
|
129
118
|
|
130
119
|
def convert_to_vlc_seconds(time_str):
|
@@ -287,8 +287,8 @@ def get_screenshot():
|
|
287
287
|
if event_id is None:
|
288
288
|
return jsonify({'error': 'Missing id'}), 400
|
289
289
|
gsm_state.line_for_screenshot = get_line_by_id(event_id)
|
290
|
-
if gsm_state.previous_line_for_screenshot and gsm_state.line_for_screenshot.id == gsm_state.previous_line_for_screenshot.id:
|
291
|
-
handle_texthooker_button()
|
290
|
+
if gsm_state.previous_line_for_screenshot and gsm_state.line_for_screenshot.id == gsm_state.previous_line_for_screenshot.id or gsm_state.previous_line_for_audio:
|
291
|
+
handle_texthooker_button(gsm_state.previous_replay)
|
292
292
|
else:
|
293
293
|
obs.save_replay_buffer()
|
294
294
|
return jsonify({}), 200
|
@@ -301,8 +301,8 @@ def play_audio():
|
|
301
301
|
if event_id is None:
|
302
302
|
return jsonify({'error': 'Missing id'}), 400
|
303
303
|
gsm_state.line_for_audio = get_line_by_id(event_id)
|
304
|
-
if gsm_state.previous_line_for_audio and gsm_state.line_for_audio == gsm_state.previous_line_for_audio:
|
305
|
-
handle_texthooker_button()
|
304
|
+
if gsm_state.previous_line_for_audio and gsm_state.line_for_audio == gsm_state.previous_line_for_audio or gsm_state.previous_line_for_screenshot:
|
305
|
+
handle_texthooker_button(gsm_state.previous_replay)
|
306
306
|
else:
|
307
307
|
obs.save_replay_buffer()
|
308
308
|
return jsonify({}), 200
|
@@ -2,7 +2,7 @@ GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
2
2
|
GameSentenceMiner/anki.py,sha256=kWw3PV_Jj5-lHcttCB3lRXejHlaAbiJ2Ag_NAGX-RI8,16632
|
3
3
|
GameSentenceMiner/config_gui.py,sha256=h-vDxpFCC347iK_mDJAjwKm7Qubeu-NWaxvd9SvzqzY,90942
|
4
4
|
GameSentenceMiner/gametext.py,sha256=6VkjmBeiuZfPk8T6PHFdIAElBH2Y_oLVYvmcafqN7RM,6747
|
5
|
-
GameSentenceMiner/gsm.py,sha256=
|
5
|
+
GameSentenceMiner/gsm.py,sha256=p4DVa_Jx1EOsgUxAAdC7st7VXLKWnP2BLDGT78ToO8w,24864
|
6
6
|
GameSentenceMiner/obs.py,sha256=ZV9Vk39hrsJLT-AlIxa3qgncKxXaL3Myl33vVJEDEoA,14670
|
7
7
|
GameSentenceMiner/vad.py,sha256=G0NkaWFJaIfKQAV7LOFxyKoih7pPNYHDuy4SzeFVCkI,16389
|
8
8
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -18,8 +18,8 @@ GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_
|
|
18
18
|
GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=0hZmNIvZmlAEcy_NaTukG_ALUORULUT7sQ8q5VlDJU4,4047
|
20
20
|
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
21
|
-
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=
|
22
|
-
GameSentenceMiner/ocr/owocr_helper.py,sha256=
|
21
|
+
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=boAqarX17jvFscu-7s6C9rqesjQ54s-kfuW0bjCru-M,19834
|
22
|
+
GameSentenceMiner/ocr/owocr_helper.py,sha256=wkrobbrBugzzRBnUO9zBnxIwMEHWVTwxfutDn2HY17c,20205
|
23
23
|
GameSentenceMiner/ocr/ss_picker.py,sha256=0IhxUdaKruFpZyBL-8SpxWg7bPrlGpy3lhTcMMZ5rwo,5224
|
24
24
|
GameSentenceMiner/owocr/owocr/__init__.py,sha256=87hfN5u_PbL_onLfMACbc0F5j4KyIK9lKnRCj6oZgR0,49
|
25
25
|
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
@@ -30,7 +30,7 @@ GameSentenceMiner/owocr/owocr/run.py,sha256=mZIGDm3fGYrYbSNuFOk7Sbslfgi36YN0YqfC
|
|
30
30
|
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
31
31
|
GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
GameSentenceMiner/util/audio_offset_selector.py,sha256=8Stk3BP-XVIuzRv9nl9Eqd2D-1yD3JrgU-CamBywJmY,8542
|
33
|
-
GameSentenceMiner/util/configuration.py,sha256=
|
33
|
+
GameSentenceMiner/util/configuration.py,sha256=wuuM39xhXahswx7EhhWXURDQ_KIPbo4RhmQ_wPEbezo,28816
|
34
34
|
GameSentenceMiner/util/electron_config.py,sha256=3VmIrcXhC-wIMMc4uqV85NrNenRl4ZUbnQfSjWEwuig,9852
|
35
35
|
GameSentenceMiner/util/ffmpeg.py,sha256=t0tflxq170n8PZKkdw8fTZIUQfXD0p_qARa9JTdhBTc,21530
|
36
36
|
GameSentenceMiner/util/gsm_utils.py,sha256=_279Fu9CU6FEh4cP6h40TWOt_BrqmPgytfumi8y53Ew,11491
|
@@ -47,8 +47,8 @@ GameSentenceMiner/util/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
47
47
|
GameSentenceMiner/util/downloader/download_tools.py,sha256=mvnOjDHFlV1AbjHaNI7mdnC5_CH5k3N4n1ezqzzbzGA,8139
|
48
48
|
GameSentenceMiner/util/downloader/oneocr_dl.py,sha256=EJbKISaZ9p2x9P4x0rpMM5nAInTTc9b7arraGBcd-SA,10381
|
49
49
|
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
|
-
GameSentenceMiner/web/service.py,sha256=
|
51
|
-
GameSentenceMiner/web/texthooking_page.py,sha256=
|
50
|
+
GameSentenceMiner/web/service.py,sha256=S7bYf2kSk08u-8R9Qpv7piM-pxfFjYZUvU825xupmuI,5279
|
51
|
+
GameSentenceMiner/web/texthooking_page.py,sha256=EmcIBEPGWNgI2LGL3kKUsm0rs2Vn0CPq9PVKKnuIt2g,16183
|
52
52
|
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
53
|
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
54
54
|
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
@@ -62,9 +62,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
62
62
|
GameSentenceMiner/web/templates/index.html,sha256=n0J-dV8eksj8JXUuaCTIh0fIxIjfgm2EvxGBdQ6gWoM,214113
|
63
63
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
64
64
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
65
|
-
gamesentenceminer-2.10.
|
66
|
-
gamesentenceminer-2.10.
|
67
|
-
gamesentenceminer-2.10.
|
68
|
-
gamesentenceminer-2.10.
|
69
|
-
gamesentenceminer-2.10.
|
70
|
-
gamesentenceminer-2.10.
|
65
|
+
gamesentenceminer-2.10.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
66
|
+
gamesentenceminer-2.10.11.dist-info/METADATA,sha256=pEHEHL90MhO8afUJ3yQTLDjdGvcYz5slrezzJ6biWfk,7355
|
67
|
+
gamesentenceminer-2.10.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
68
|
+
gamesentenceminer-2.10.11.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
69
|
+
gamesentenceminer-2.10.11.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
70
|
+
gamesentenceminer-2.10.11.dist-info/RECORD,,
|
File without changes
|
{gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/entry_points.txt
RENAMED
File without changes
|
{gamesentenceminer-2.10.10.dist-info → gamesentenceminer-2.10.11.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|