GameSentenceMiner 2.18.20__py3-none-any.whl → 2.19.0__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.
Potentially problematic release.
This version of GameSentenceMiner might be problematic. Click here for more details.
- GameSentenceMiner/gametext.py +73 -15
- GameSentenceMiner/gsm.py +7 -49
- GameSentenceMiner/obs.py +25 -2
- GameSentenceMiner/ui/config_gui.py +29 -17
- GameSentenceMiner/util/communication/send.py +13 -1
- GameSentenceMiner/util/communication/websocket.py +2 -2
- GameSentenceMiner/util/configuration.py +3 -15
- GameSentenceMiner/util/db.py +1 -1
- GameSentenceMiner/util/downloader/download_tools.py +53 -27
- GameSentenceMiner/util/get_overlay_coords.py +24 -4
- GameSentenceMiner/web/events.py +31 -107
- GameSentenceMiner/web/templates/anki_stats.html +1 -0
- GameSentenceMiner/web/templates/index.html +12 -12
- GameSentenceMiner/web/texthooking_page.py +15 -2
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/METADATA +15 -5
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/RECORD +20 -20
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.18.20.dist-info → gamesentenceminer-2.19.0.dist-info}/top_level.txt +0 -0
|
@@ -83,6 +83,8 @@ try:
|
|
|
83
83
|
except ImportError:
|
|
84
84
|
mss = None
|
|
85
85
|
|
|
86
|
+
overlay_processor = None
|
|
87
|
+
|
|
86
88
|
class OverlayThread(threading.Thread):
|
|
87
89
|
"""
|
|
88
90
|
A thread to run the overlay processing loop.
|
|
@@ -91,7 +93,6 @@ class OverlayThread(threading.Thread):
|
|
|
91
93
|
"""
|
|
92
94
|
def __init__(self):
|
|
93
95
|
super().__init__()
|
|
94
|
-
self.overlay_processor = OverlayProcessor()
|
|
95
96
|
self.loop = asyncio.new_event_loop()
|
|
96
97
|
self.daemon = True
|
|
97
98
|
self.first_time_run = True
|
|
@@ -106,10 +107,10 @@ class OverlayThread(threading.Thread):
|
|
|
106
107
|
while True:
|
|
107
108
|
if overlay_server_thread.has_clients():
|
|
108
109
|
if get_config().overlay.periodic:
|
|
109
|
-
await
|
|
110
|
+
await overlay_processor.find_box_and_send_to_overlay('', True)
|
|
110
111
|
await asyncio.sleep(get_config().overlay.periodic_interval)
|
|
111
112
|
elif self.first_time_run:
|
|
112
|
-
await
|
|
113
|
+
await overlay_processor.find_box_and_send_to_overlay('', False)
|
|
113
114
|
self.first_time_run = False
|
|
114
115
|
else:
|
|
115
116
|
await asyncio.sleep(3)
|
|
@@ -569,7 +570,26 @@ class OverlayProcessor:
|
|
|
569
570
|
# logger.info(f"Converted OneOCR results to percentages: {converted_results}")
|
|
570
571
|
return converted_results
|
|
571
572
|
|
|
572
|
-
|
|
573
|
+
async def init_overlay_processor():
|
|
574
|
+
"""
|
|
575
|
+
Initializes the overlay processor and starts the overlay thread.
|
|
576
|
+
This function can be called at application startup.
|
|
577
|
+
"""
|
|
578
|
+
global overlay_processor
|
|
579
|
+
overlay_processor = OverlayProcessor()
|
|
580
|
+
overlay_thread = OverlayThread()
|
|
581
|
+
overlay_thread.start()
|
|
582
|
+
logger.info("Overlay processor initialized and thread started.")
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def get_overlay_processor() -> OverlayProcessor:
|
|
586
|
+
"""
|
|
587
|
+
Returns the initialized overlay processor instance.
|
|
588
|
+
"""
|
|
589
|
+
global overlay_processor
|
|
590
|
+
if overlay_processor is None:
|
|
591
|
+
asyncio.run(init_overlay_processor())
|
|
592
|
+
return overlay_processor
|
|
573
593
|
|
|
574
594
|
async def main_test_screenshot():
|
|
575
595
|
"""
|
GameSentenceMiner/web/events.py
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
from collections import defaultdict
|
|
3
1
|
import datetime
|
|
4
|
-
import json
|
|
5
|
-
import os
|
|
6
|
-
import queue
|
|
7
|
-
import sqlite3
|
|
8
|
-
import threading
|
|
9
2
|
from dataclasses import dataclass
|
|
10
3
|
|
|
11
|
-
from GameSentenceMiner.util.
|
|
12
|
-
from GameSentenceMiner.util.text_log import GameLine, initial_time
|
|
13
|
-
from GameSentenceMiner.util.configuration import logger, DB_PATH
|
|
4
|
+
from GameSentenceMiner.util.text_log import GameLine
|
|
14
5
|
|
|
15
6
|
|
|
16
7
|
@dataclass
|
|
@@ -42,60 +33,30 @@ class EventItem:
|
|
|
42
33
|
|
|
43
34
|
|
|
44
35
|
class EventManager:
|
|
36
|
+
ids: set[str] = set()
|
|
45
37
|
events: list[EventItem]
|
|
46
38
|
events_dict: dict[str, EventItem] = {}
|
|
47
39
|
|
|
48
40
|
def __init__(self):
|
|
49
41
|
self.events = []
|
|
50
|
-
self.ids =
|
|
42
|
+
self.ids = set()
|
|
43
|
+
self.timed_out_ids = set()
|
|
51
44
|
self.events_dict = {}
|
|
52
|
-
self._connect()
|
|
53
|
-
self._create_table()
|
|
54
|
-
self._load_events_from_db()
|
|
55
|
-
# self.close_connection()
|
|
56
|
-
|
|
57
|
-
def _connect(self):
|
|
58
|
-
self.conn = sqlite3.connect(DB_PATH)
|
|
59
|
-
self.cursor = self.conn.cursor()
|
|
60
|
-
|
|
61
|
-
def _create_table(self):
|
|
62
|
-
self.cursor.execute("""
|
|
63
|
-
CREATE TABLE IF NOT EXISTS events (
|
|
64
|
-
event_id TEXT PRIMARY KEY,
|
|
65
|
-
line_id TEXT,
|
|
66
|
-
text TEXT,
|
|
67
|
-
time TEXT
|
|
68
|
-
)
|
|
69
|
-
""")
|
|
70
|
-
self.conn.commit()
|
|
71
|
-
|
|
72
|
-
def _load_events_from_db(self):
|
|
73
|
-
self.cursor.execute("SELECT * FROM events")
|
|
74
|
-
rows = self.cursor.fetchall()
|
|
75
|
-
for row in rows:
|
|
76
|
-
event_id, line_id, text, timestamp = row
|
|
77
|
-
timestamp = datetime.datetime.fromisoformat(timestamp)
|
|
78
|
-
line = GameLine(line_id, text, timestamp, None, None, 0)
|
|
79
|
-
event = EventItem(line, event_id, text, timestamp,
|
|
80
|
-
False, timestamp < initial_time)
|
|
81
|
-
self.events.append(event)
|
|
82
|
-
self.ids.append(event_id)
|
|
83
|
-
self.events_dict[event_id] = event
|
|
84
45
|
|
|
85
46
|
def __iter__(self):
|
|
86
47
|
return iter(self.events)
|
|
87
48
|
|
|
88
49
|
def replace_events(self, new_events: list[EventItem]):
|
|
89
50
|
self.events = new_events
|
|
51
|
+
self.events_dict = {event.id: event for event in new_events}
|
|
52
|
+
self.ids = {event.id for event in new_events}
|
|
90
53
|
|
|
91
54
|
def add_gameline(self, line: GameLine):
|
|
92
55
|
new_event = EventItem(line, line.id, line.text,
|
|
93
56
|
line.time, False, False)
|
|
94
57
|
self.events_dict[line.id] = new_event
|
|
95
|
-
self.ids.
|
|
58
|
+
self.ids.add(line.id)
|
|
96
59
|
self.events.append(new_event)
|
|
97
|
-
# self.store_to_db(new_event)
|
|
98
|
-
# event_queue.put(new_event)
|
|
99
60
|
return new_event
|
|
100
61
|
|
|
101
62
|
def reset_checked_lines(self):
|
|
@@ -107,8 +68,7 @@ class EventManager:
|
|
|
107
68
|
|
|
108
69
|
def add_event(self, event):
|
|
109
70
|
self.events.append(event)
|
|
110
|
-
self.ids.
|
|
111
|
-
event_queue.put(event)
|
|
71
|
+
self.ids.add(event.id)
|
|
112
72
|
|
|
113
73
|
def get(self, event_id):
|
|
114
74
|
return self.events_dict.get(event_id)
|
|
@@ -116,63 +76,27 @@ class EventManager:
|
|
|
116
76
|
def get_ids(self):
|
|
117
77
|
return self.ids
|
|
118
78
|
|
|
119
|
-
def close_connection(self):
|
|
120
|
-
if self.conn:
|
|
121
|
-
self.conn.close()
|
|
122
|
-
|
|
123
79
|
def clear_history(self):
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
self.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
self.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def run(self):
|
|
149
|
-
self._connect()
|
|
150
|
-
while True:
|
|
151
|
-
try:
|
|
152
|
-
event = self.event_queue.get()
|
|
153
|
-
if event is None: # Exit signal
|
|
154
|
-
break
|
|
155
|
-
self._store_to_db(event)
|
|
156
|
-
except Exception as e:
|
|
157
|
-
logger.error(f"Error processing event: {e}")
|
|
158
|
-
self._close_connection()
|
|
159
|
-
|
|
160
|
-
def _store_to_db(self, event):
|
|
161
|
-
self.cursor.execute("""
|
|
162
|
-
INSERT INTO events (event_id, line_id, text, time)
|
|
163
|
-
VALUES (?, ?, ?, ?)
|
|
164
|
-
""", (event.id, event.line.id, event.text, event.time.isoformat()))
|
|
165
|
-
self.conn.commit()
|
|
166
|
-
|
|
167
|
-
def _close_connection(self):
|
|
168
|
-
if self.conn:
|
|
169
|
-
self.conn.close()
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Global instances
|
|
173
|
-
event_manager = EventManager()
|
|
174
|
-
event_queue = queue.Queue()
|
|
175
|
-
|
|
176
|
-
# Initialize the EventProcessor with the queue and event manager
|
|
177
|
-
event_processor = EventProcessor(event_queue, DB_PATH)
|
|
178
|
-
event_processor.start()
|
|
80
|
+
# Clear the in-memory events
|
|
81
|
+
self.events = [
|
|
82
|
+
event for event in self.events if not event.history]
|
|
83
|
+
self.events_dict = {
|
|
84
|
+
event.id: event for event in self.events}
|
|
85
|
+
self.ids = {event.id for event in self.events}
|
|
86
|
+
|
|
87
|
+
def remove_lines_by_ids(self, ids: list[str], timed_out: bool = False):
|
|
88
|
+
ids_to_remove = set(ids)
|
|
89
|
+
|
|
90
|
+
self.events = [event for event in self.events if event.id not in ids_to_remove]
|
|
91
|
+
|
|
92
|
+
for event_id in ids_to_remove:
|
|
93
|
+
self.events_dict.pop(event_id, None)
|
|
94
|
+
|
|
95
|
+
# Remove from set (much more efficient than rebuilding)
|
|
96
|
+
self.ids -= ids_to_remove
|
|
97
|
+
if timed_out:
|
|
98
|
+
self.timed_out_ids.update(ids_to_remove)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# Global instance
|
|
102
|
+
event_manager = EventManager()
|