GameSentenceMiner 2.9.3__py3-none-any.whl → 2.9.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 +4 -0
- GameSentenceMiner/assets/__init__.py +0 -0
- GameSentenceMiner/assets/icon.png +0 -0
- GameSentenceMiner/assets/icon128.png +0 -0
- GameSentenceMiner/assets/icon256.png +0 -0
- GameSentenceMiner/assets/icon32.png +0 -0
- GameSentenceMiner/assets/icon512.png +0 -0
- GameSentenceMiner/assets/icon64.png +0 -0
- GameSentenceMiner/assets/pickaxe.png +0 -0
- GameSentenceMiner/notification.py +21 -0
- GameSentenceMiner/obs.py +0 -1
- GameSentenceMiner/package.py +0 -1
- GameSentenceMiner/web/texthooking_page.py +69 -51
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/RECORD +19 -11
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.9.3.dist-info → gamesentenceminer-2.9.4.dist-info}/top_level.txt +0 -0
GameSentenceMiner/anki.py
CHANGED
@@ -82,6 +82,8 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
82
82
|
for key, value in get_config().anki.anki_custom_fields.items():
|
83
83
|
note['fields'][key] = str(value)
|
84
84
|
|
85
|
+
|
86
|
+
notification.open_browser_window(1)
|
85
87
|
invoke("updateNoteFields", note=note)
|
86
88
|
tags = []
|
87
89
|
if get_config().anki.custom_tags:
|
@@ -94,9 +96,11 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
94
96
|
logger.info(f"UPDATED ANKI CARD FOR {last_note.noteId}")
|
95
97
|
if get_config().features.notify_on_update:
|
96
98
|
notification.send_note_updated(tango)
|
99
|
+
notification.open_browser_window(last_note.noteId)
|
97
100
|
if get_config().features.open_anki_edit:
|
98
101
|
notification.open_anki_card(last_note.noteId)
|
99
102
|
|
103
|
+
|
100
104
|
if get_config().audio.external_tool and get_config().audio.external_tool_enabled and update_audio:
|
101
105
|
open_audio_in_external(f"{get_config().audio.anki_media_collection}/{audio_in_anki}")
|
102
106
|
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -21,6 +21,27 @@ if is_windows():
|
|
21
21
|
else:
|
22
22
|
notifier = notification
|
23
23
|
|
24
|
+
def open_browser_window(note_id):
|
25
|
+
url = "http://localhost:8765"
|
26
|
+
headers = {'Content-Type': 'application/json'}
|
27
|
+
|
28
|
+
data = {
|
29
|
+
"action": "guiBrowse",
|
30
|
+
"version": 6,
|
31
|
+
"params": {
|
32
|
+
"query": f"nid:{note_id}"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
try:
|
37
|
+
response = requests.post(url, json=data, headers=headers)
|
38
|
+
if response.status_code == 200:
|
39
|
+
logger.info(f"Opened Anki note with ID {note_id}")
|
40
|
+
else:
|
41
|
+
logger.error(f"Failed to open Anki note with ID {note_id}")
|
42
|
+
except Exception as e:
|
43
|
+
logger.info(f"Error connecting to AnkiConnect: {e}")
|
44
|
+
|
24
45
|
|
25
46
|
def open_anki_card(note_id):
|
26
47
|
url = "http://localhost:8765"
|
GameSentenceMiner/obs.py
CHANGED
GameSentenceMiner/package.py
CHANGED
@@ -247,7 +247,7 @@ def clear_history():
|
|
247
247
|
|
248
248
|
async def add_event_to_texthooker(line: GameLine):
|
249
249
|
new_event = event_manager.add_gameline(line)
|
250
|
-
await
|
250
|
+
await websocket_server_thread.send_text({
|
251
251
|
'event': 'text_received',
|
252
252
|
'sentence': line.text,
|
253
253
|
'data': new_event.to_serializable()
|
@@ -294,37 +294,6 @@ def play_audio():
|
|
294
294
|
return jsonify({}), 200
|
295
295
|
|
296
296
|
|
297
|
-
connected_clients = set()
|
298
|
-
|
299
|
-
async def websocket_handler(websocket):
|
300
|
-
logger.debug(f"Client connected: {websocket.remote_address}")
|
301
|
-
connected_clients.add(websocket)
|
302
|
-
try:
|
303
|
-
async for message in websocket:
|
304
|
-
try:
|
305
|
-
data = json.loads(message)
|
306
|
-
if 'type' in data and data['type'] == 'get_events':
|
307
|
-
initial_events = [{'id': 1, 'text': 'Initial event from WebSocket'}, {'id': 2, 'text': 'Another initial event'}]
|
308
|
-
await websocket.send(json.dumps({'event': 'initial_events', 'payload': initial_events}))
|
309
|
-
elif 'update_checkbox' in data:
|
310
|
-
print(f"Received checkbox update: {data}")
|
311
|
-
# Handle checkbox update logic
|
312
|
-
pass
|
313
|
-
await websocket.send(json.dumps({'response': f'Server received: {message}'}))
|
314
|
-
except json.JSONDecodeError:
|
315
|
-
await websocket.send(json.dumps({'error': 'Invalid JSON format'}))
|
316
|
-
except websockets.exceptions.ConnectionClosedError:
|
317
|
-
print(f"Client disconnected abruptly: {websocket.remote_address}")
|
318
|
-
except websockets.exceptions.ConnectionClosedOK:
|
319
|
-
print(f"Client disconnected gracefully: {websocket.remote_address}")
|
320
|
-
finally:
|
321
|
-
connected_clients.discard(websocket)
|
322
|
-
|
323
|
-
async def broadcast_message(message):
|
324
|
-
if connected_clients:
|
325
|
-
for client in connected_clients:
|
326
|
-
await client.send(json.dumps(message))
|
327
|
-
|
328
297
|
# async def main():
|
329
298
|
# async with websockets.serve(websocket_handler, "localhost", 8765): # Choose a port for WebSocket
|
330
299
|
# print("WebSocket server started on ws://localhost:8765/ws (adjust as needed)")
|
@@ -360,7 +329,7 @@ def are_lines_selected():
|
|
360
329
|
|
361
330
|
def reset_checked_lines():
|
362
331
|
async def send_reset_message():
|
363
|
-
await
|
332
|
+
await websocket_server_thread.send_text({
|
364
333
|
'event': 'reset_checkboxes',
|
365
334
|
})
|
366
335
|
event_manager.reset_checked_lines()
|
@@ -383,23 +352,69 @@ def start_web_server():
|
|
383
352
|
|
384
353
|
import signal
|
385
354
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
355
|
+
websocket_server_thread = None
|
356
|
+
websocket_queue = queue.Queue()
|
357
|
+
paused = False
|
358
|
+
|
359
|
+
|
360
|
+
class WebsocketServerThread(threading.Thread):
|
361
|
+
def __init__(self, read):
|
362
|
+
super().__init__(daemon=True)
|
363
|
+
self._loop = None
|
364
|
+
self.read = read
|
365
|
+
self.clients = set()
|
366
|
+
self._event = threading.Event()
|
367
|
+
|
368
|
+
@property
|
369
|
+
def loop(self):
|
370
|
+
self._event.wait()
|
371
|
+
return self._loop
|
372
|
+
|
373
|
+
async def send_text_coroutine(self, message):
|
374
|
+
for client in self.clients:
|
375
|
+
await client.send(message)
|
376
|
+
|
377
|
+
async def server_handler(self, websocket):
|
378
|
+
self.clients.add(websocket)
|
379
|
+
try:
|
380
|
+
async for message in websocket:
|
381
|
+
if self.read and not paused:
|
382
|
+
websocket_queue.put(message)
|
383
|
+
try:
|
384
|
+
await websocket.send('True')
|
385
|
+
except websockets.exceptions.ConnectionClosedOK:
|
386
|
+
pass
|
387
|
+
else:
|
388
|
+
try:
|
389
|
+
await websocket.send('False')
|
390
|
+
except websockets.exceptions.ConnectionClosedOK:
|
391
|
+
pass
|
392
|
+
except websockets.exceptions.ConnectionClosedError:
|
393
|
+
pass
|
394
|
+
finally:
|
395
|
+
self.clients.remove(websocket)
|
396
|
+
|
397
|
+
async def send_text(self, text):
|
398
|
+
if text:
|
399
|
+
return asyncio.run_coroutine_threadsafe(
|
400
|
+
self.send_text_coroutine(json.dumps(text)), self.loop)
|
401
|
+
|
402
|
+
def stop_server(self):
|
403
|
+
self.loop.call_soon_threadsafe(self._stop_event.set)
|
404
|
+
|
405
|
+
def run(self):
|
406
|
+
async def main():
|
407
|
+
self._loop = asyncio.get_running_loop()
|
408
|
+
self._stop_event = stop_event = asyncio.Event()
|
409
|
+
self._event.set()
|
410
|
+
self.server = start_server = websockets.serve(self.server_handler,
|
411
|
+
"0.0.0.0",
|
412
|
+
get_config().advanced.texthooker_communication_websocket_port,
|
413
|
+
max_size=1000000000)
|
414
|
+
async with start_server:
|
415
|
+
await stop_event.wait()
|
416
|
+
|
417
|
+
asyncio.run(main())
|
403
418
|
|
404
419
|
def handle_exit_signal(loop):
|
405
420
|
logger.info("Received exit signal. Shutting down...")
|
@@ -407,13 +422,16 @@ def handle_exit_signal(loop):
|
|
407
422
|
task.cancel()
|
408
423
|
|
409
424
|
async def texthooker_page_coro():
|
425
|
+
global websocket_server_thread
|
410
426
|
# Run the WebSocket server in the asyncio event loop
|
411
427
|
flask_thread = threading.Thread(target=start_web_server)
|
412
428
|
flask_thread.daemon = True
|
413
429
|
flask_thread.start()
|
414
430
|
|
431
|
+
websocket_server_thread = WebsocketServerThread(read=True)
|
432
|
+
websocket_server_thread.start()
|
433
|
+
|
415
434
|
# Keep the main asyncio event loop running (for the WebSocket server)
|
416
|
-
await run_websocket_server()
|
417
435
|
|
418
436
|
def run_text_hooker_page():
|
419
437
|
try:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=
|
2
|
+
GameSentenceMiner/anki.py,sha256=HAYblBjkth5p0tx9Z0LNQn6zuQC8_54RIB2BMzN8-LE,14705
|
3
3
|
GameSentenceMiner/config_gui.py,sha256=h4zz85gfhxSphaJ-IZSu9D4jR70mDlKecZ9JRCO5Noc,80927
|
4
4
|
GameSentenceMiner/configuration.py,sha256=KKW6fmpxya4dmXx9cERFVrzsKCTw0vmZrF2HAJDURBU,25667
|
5
5
|
GameSentenceMiner/electron_config.py,sha256=dGcPYCISPehXubYSzsDuI2Gl092MYK0u3bTnkL9Jh1Y,9787
|
@@ -7,14 +7,22 @@ GameSentenceMiner/ffmpeg.py,sha256=APa2vNdAgxYdG96_Z3Xdh1WqOiWaK6gTLJqzEvCMMeU,1
|
|
7
7
|
GameSentenceMiner/gametext.py,sha256=sll-6Pficd4ZXYy8yL8hBrEOSpfa53TOye7vtHHKFN4,6218
|
8
8
|
GameSentenceMiner/gsm.py,sha256=olG3BIWjbVHWTsRKmeDVE5X8XrgppWke73Fy1J15dxA,29868
|
9
9
|
GameSentenceMiner/model.py,sha256=1lRyJFf_LND_4O16h8CWVqDfosLgr0ZS6ufBZ3qJHpY,5699
|
10
|
-
GameSentenceMiner/notification.py,sha256=
|
11
|
-
GameSentenceMiner/obs.py,sha256=
|
12
|
-
GameSentenceMiner/package.py,sha256=
|
10
|
+
GameSentenceMiner/notification.py,sha256=e6TOzZJD7RTvMgxaY-V01r5OiocHhdqEIVdAnj4MGSw,3437
|
11
|
+
GameSentenceMiner/obs.py,sha256=JiydRMpfSpNZ0nDAzH8OOECbYbsxMNSGz46lO8lZbvA,14871
|
12
|
+
GameSentenceMiner/package.py,sha256=uu3Yb3pqu8vN5ISzP87YCHlFNR9wxMMf5hPRncTr7ws,1181
|
13
13
|
GameSentenceMiner/ss_selector.py,sha256=csey9H3561-guRJcT6gQN6hXxvylP0CBI0dp2-kwo2Q,4446
|
14
14
|
GameSentenceMiner/text_log.py,sha256=U2_g8THAYeexRiE2bLk_bCt_2ShiA8SQ9VdJsi4riHs,5181
|
15
15
|
GameSentenceMiner/util.py,sha256=ZbK7i1UeOzKyc5WtCcttiGljR_stfu7qpnEpgqFBwro,8976
|
16
16
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
GameSentenceMiner/ai/ai_prompting.py,sha256=xw8et6XNwQiDXOXZnw8iIntVSg8lni4YYZbgWsK7qDE,10013
|
18
|
+
GameSentenceMiner/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
GameSentenceMiner/assets/icon.png,sha256=9GRL8uXUAgkUSlvbm9Pv9o2poFVRGdW6s2ub_DeUD9M,937624
|
20
|
+
GameSentenceMiner/assets/icon128.png,sha256=l90j7biwdz5ahwOd5wZ-406ryEV9Pan93dquJQ3e1CI,18395
|
21
|
+
GameSentenceMiner/assets/icon256.png,sha256=JEW46wOrG1KR-907rvFaEdNbPtj5gu0HJmG7qUnIHxQ,51874
|
22
|
+
GameSentenceMiner/assets/icon32.png,sha256=Kww0hU_qke9_22wBuO_Nq0Dv2SfnOLwMhCyGgbgXdg8,6089
|
23
|
+
GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB_7W4sqs,192487
|
24
|
+
GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
|
25
|
+
GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
|
18
26
|
GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
|
19
27
|
GameSentenceMiner/communication/send.py,sha256=X0MytGv5hY-uUvkfvdCqQA_ljZFmV6UkJ6in1TA1bUE,217
|
20
28
|
GameSentenceMiner/communication/websocket.py,sha256=8eFZaTtoFggEPdqw2Jl4zqHC2I7J3-Gk27CxVX7SyBo,3277
|
@@ -42,7 +50,7 @@ GameSentenceMiner/vad/vad_utils.py,sha256=_YC6rW2eXSBeLnYbVl_F3na1KCRL90VrnOzKYJ
|
|
42
50
|
GameSentenceMiner/vad/vosk_helper.py,sha256=h7yNHrzrzT-J74UniA0T2ZX8cHqhflCzwyDjoIdKLO4,6479
|
43
51
|
GameSentenceMiner/vad/whisper_helper.py,sha256=B64-Eq_ZMCIyQX_A8uvYz-c48hSXJAyz6tSXNRaLjtA,4020
|
44
52
|
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
|
-
GameSentenceMiner/web/texthooking_page.py,sha256=
|
53
|
+
GameSentenceMiner/web/texthooking_page.py,sha256=7Z7TGDcnj-94Y9ws7bQph4oIXrqf8Q9qVKowKimHWxM,14749
|
46
54
|
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
55
|
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
48
56
|
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
@@ -56,9 +64,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
56
64
|
GameSentenceMiner/web/templates/index.html,sha256=HZKiIjiGJV8PGQ9T2aLDUNSfJn71qOwbYCjbRuSIjpY,213583
|
57
65
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
58
66
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
59
|
-
gamesentenceminer-2.9.
|
60
|
-
gamesentenceminer-2.9.
|
61
|
-
gamesentenceminer-2.9.
|
62
|
-
gamesentenceminer-2.9.
|
63
|
-
gamesentenceminer-2.9.
|
64
|
-
gamesentenceminer-2.9.
|
67
|
+
gamesentenceminer-2.9.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
68
|
+
gamesentenceminer-2.9.4.dist-info/METADATA,sha256=jNhOj4IaiTEJqGlm4-VCtviW5hmN8J5XnvPBGWgcY0Y,7280
|
69
|
+
gamesentenceminer-2.9.4.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
70
|
+
gamesentenceminer-2.9.4.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
71
|
+
gamesentenceminer-2.9.4.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
72
|
+
gamesentenceminer-2.9.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|