GameSentenceMiner 2.14.9__py3-none-any.whl → 2.14.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/ai/__init__.py +0 -0
- GameSentenceMiner/ai/ai_prompting.py +473 -0
- GameSentenceMiner/ocr/__init__.py +0 -0
- GameSentenceMiner/ocr/gsm_ocr_config.py +174 -0
- GameSentenceMiner/ocr/ocrconfig.py +129 -0
- GameSentenceMiner/ocr/owocr_area_selector.py +629 -0
- GameSentenceMiner/ocr/owocr_helper.py +638 -0
- GameSentenceMiner/ocr/ss_picker.py +140 -0
- GameSentenceMiner/owocr/owocr/__init__.py +1 -0
- GameSentenceMiner/owocr/owocr/__main__.py +9 -0
- GameSentenceMiner/owocr/owocr/config.py +148 -0
- GameSentenceMiner/owocr/owocr/lens_betterproto.py +1238 -0
- GameSentenceMiner/owocr/owocr/ocr.py +1690 -0
- GameSentenceMiner/owocr/owocr/run.py +1818 -0
- GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +109 -0
- GameSentenceMiner/tools/__init__.py +0 -0
- GameSentenceMiner/tools/audio_offset_selector.py +215 -0
- GameSentenceMiner/tools/ss_selector.py +135 -0
- GameSentenceMiner/tools/window_transparency.py +214 -0
- GameSentenceMiner/util/__init__.py +0 -0
- GameSentenceMiner/util/communication/__init__.py +22 -0
- GameSentenceMiner/util/communication/send.py +7 -0
- GameSentenceMiner/util/communication/websocket.py +94 -0
- GameSentenceMiner/util/configuration.py +1199 -0
- GameSentenceMiner/util/db.py +408 -0
- GameSentenceMiner/util/downloader/Untitled_json.py +472 -0
- GameSentenceMiner/util/downloader/__init__.py +0 -0
- GameSentenceMiner/util/downloader/download_tools.py +194 -0
- GameSentenceMiner/util/downloader/oneocr_dl.py +250 -0
- GameSentenceMiner/util/electron_config.py +259 -0
- GameSentenceMiner/util/ffmpeg.py +571 -0
- GameSentenceMiner/util/get_overlay_coords.py +366 -0
- GameSentenceMiner/util/gsm_utils.py +323 -0
- GameSentenceMiner/util/model.py +206 -0
- GameSentenceMiner/util/notification.py +157 -0
- GameSentenceMiner/util/text_log.py +214 -0
- GameSentenceMiner/util/win10toast/__init__.py +154 -0
- GameSentenceMiner/util/win10toast/__main__.py +22 -0
- GameSentenceMiner/web/__init__.py +0 -0
- GameSentenceMiner/web/service.py +132 -0
- GameSentenceMiner/web/static/__init__.py +0 -0
- GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- GameSentenceMiner/web/static/favicon.ico +0 -0
- GameSentenceMiner/web/static/favicon.svg +3 -0
- GameSentenceMiner/web/static/site.webmanifest +21 -0
- GameSentenceMiner/web/static/style.css +292 -0
- GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- GameSentenceMiner/web/templates/__init__.py +0 -0
- GameSentenceMiner/web/templates/index.html +50 -0
- GameSentenceMiner/web/templates/text_replacements.html +238 -0
- GameSentenceMiner/web/templates/utility.html +483 -0
- GameSentenceMiner/web/texthooking_page.py +584 -0
- GameSentenceMiner/wip/__init___.py +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.11.dist-info}/METADATA +1 -1
- gamesentenceminer-2.14.11.dist-info/RECORD +79 -0
- gamesentenceminer-2.14.9.dist-info/RECORD +0 -24
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.11.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.11.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.11.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,483 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>GSM TextHooker</title>
|
6
|
+
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
7
|
+
<style>
|
8
|
+
body {
|
9
|
+
background-color: #121212;
|
10
|
+
color: #e0e0e0;
|
11
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
12
|
+
margin: 20px;
|
13
|
+
}
|
14
|
+
|
15
|
+
h2 {
|
16
|
+
color: #ffffff;
|
17
|
+
text-align: center;
|
18
|
+
font-weight: 300;
|
19
|
+
margin-bottom: 20px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.textline {
|
23
|
+
margin: 15px 0;
|
24
|
+
padding: 15px;
|
25
|
+
display: flex;
|
26
|
+
align-items: center;
|
27
|
+
gap: 15px;
|
28
|
+
}
|
29
|
+
.textline:last-child {
|
30
|
+
border-bottom: none;
|
31
|
+
}
|
32
|
+
|
33
|
+
.textline > p {
|
34
|
+
font-size: 24px;
|
35
|
+
flex: 1;
|
36
|
+
min-width: 200px;
|
37
|
+
}
|
38
|
+
|
39
|
+
.textline > em {
|
40
|
+
color: #aaa;
|
41
|
+
font-size: 0.9em;
|
42
|
+
margin-right: 10px;
|
43
|
+
}
|
44
|
+
|
45
|
+
.textline > button {
|
46
|
+
background-color: #1a73e8;
|
47
|
+
color: #ffffff;
|
48
|
+
border: none;
|
49
|
+
padding: 8px 15px;
|
50
|
+
font-size: 14px;
|
51
|
+
cursor: pointer;
|
52
|
+
transition: background-color 0.3s;
|
53
|
+
border-radius: 5px;
|
54
|
+
user-select: none; /* Make text unselectable */
|
55
|
+
}
|
56
|
+
|
57
|
+
.textline > button:hover {
|
58
|
+
background-color: #1669c1;
|
59
|
+
cursor: pointer;
|
60
|
+
}
|
61
|
+
|
62
|
+
.textline-buttons {
|
63
|
+
margin-left: auto; /* Align buttons to the right */
|
64
|
+
display: flex;
|
65
|
+
gap: 10px;
|
66
|
+
}
|
67
|
+
|
68
|
+
@media (max-width: 600px) {
|
69
|
+
.textline {
|
70
|
+
flex-direction: column;
|
71
|
+
align-items: flex-start;
|
72
|
+
}
|
73
|
+
.textline-buttons{
|
74
|
+
margin-top: 10px;
|
75
|
+
}
|
76
|
+
.textline > strong{
|
77
|
+
min-width: auto;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
.initial-event {
|
82
|
+
margin: 15px 0;
|
83
|
+
padding: 15px;
|
84
|
+
}
|
85
|
+
|
86
|
+
hr.initial-events-separator {
|
87
|
+
border: 0;
|
88
|
+
border-top: 2px solid #aaa;
|
89
|
+
margin: 20px 0;
|
90
|
+
}
|
91
|
+
|
92
|
+
.multi-line-checkbox {
|
93
|
+
transform: scale(1.5);
|
94
|
+
margin-right: 10px;
|
95
|
+
background-color: #00FFFF !important; /* Cyan/Electric Blue */
|
96
|
+
border: 4px solid #00FFFF; /* Keep the border the same color */
|
97
|
+
}
|
98
|
+
|
99
|
+
.multi-line-checkbox:checked {
|
100
|
+
/* You'll likely need to target the checkmark specifically */
|
101
|
+
/* Example assuming it's a pseudo-element with a font-based check: */
|
102
|
+
/* &::before { */
|
103
|
+
/* color: #FFFF00; /* Bright Yellow */
|
104
|
+
/* } */
|
105
|
+
/* If it's a background image, you might need to adjust the background or use a filter. */
|
106
|
+
}
|
107
|
+
|
108
|
+
</style>
|
109
|
+
</head>
|
110
|
+
<body>
|
111
|
+
<div style="position: fixed; top: 20px; right: 20px; display: flex; gap: 10px;">
|
112
|
+
<button onclick="window.location.href='/textreplacements'" style="background-color: #1a73e8; color: #ffffff; border: none; padding: 10px 20px; font-size: 12px; cursor: pointer; transition: background-color 0.3s; border-radius: 5px;">
|
113
|
+
Text Replacements
|
114
|
+
</button>
|
115
|
+
<button id="delete-history" style="background-color: #1a73e8; color: #ffffff; border: none; padding: 10px 20px; font-size: 12px; cursor: pointer; transition: background-color 0.3s; border-radius: 5px;">
|
116
|
+
Clear History
|
117
|
+
</button>
|
118
|
+
</div>
|
119
|
+
<div id="initial-events">
|
120
|
+
|
121
|
+
</div>
|
122
|
+
<hr class="initial-events-separator" id="initial-events-separator" style="display: none;">
|
123
|
+
<div id="session-events">
|
124
|
+
|
125
|
+
</div>
|
126
|
+
<script>
|
127
|
+
let mainStyle = document.querySelector('head style');
|
128
|
+
let deleteHistoryButton = document.getElementById('delete-history');
|
129
|
+
let displayedEventIds = new Set();
|
130
|
+
let isTabActive = true;
|
131
|
+
let isFetching = false; // Flag to track if a fetch is in progress
|
132
|
+
let intervalId = 0;
|
133
|
+
const fetchInterval = 100; // Define the interval as a constant
|
134
|
+
const websocketPort = {{ websocket_port }} || 55001;
|
135
|
+
|
136
|
+
// Drag selection variables
|
137
|
+
let isDragging = false;
|
138
|
+
let dragStartCheckbox = null;
|
139
|
+
let newCheckboxState = false;
|
140
|
+
let hoveredCheckboxes = new Set();
|
141
|
+
let checkboxes = []; // Will hold all checkbox elements
|
142
|
+
let checkboxMap = {};
|
143
|
+
let textLines = []; // Will hold all textline elements
|
144
|
+
let textLineMap = {};
|
145
|
+
let checkboxes_being_updated = new Set();
|
146
|
+
|
147
|
+
// Shift click selection variable
|
148
|
+
let lastChecked = null;
|
149
|
+
|
150
|
+
|
151
|
+
async function fetchEvents() {
|
152
|
+
if (document.hidden || isFetching) {
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
isFetching = true
|
156
|
+
try {
|
157
|
+
const res = await fetch('/data');
|
158
|
+
if (!res.ok) {
|
159
|
+
throw new Error(`HTTP error! Status: ${res.status}`);
|
160
|
+
}
|
161
|
+
const events = await res.json();
|
162
|
+
|
163
|
+
let historyEvents = []
|
164
|
+
events.forEach(ev => {
|
165
|
+
if (!displayedEventIds.has(ev.id)) {
|
166
|
+
if (ev.history) {
|
167
|
+
historyEvents.push(ev);
|
168
|
+
document.getElementById('initial-events-separator').style.display = 'block';
|
169
|
+
} else {
|
170
|
+
addNewEvent(ev)
|
171
|
+
}
|
172
|
+
}
|
173
|
+
if (!ev.history) {
|
174
|
+
if (!checkboxes_being_updated.has(ev.id)) {
|
175
|
+
const checkbox = checkboxMap[ev.id];
|
176
|
+
if (checkbox) {
|
177
|
+
checkbox.checked = ev.checked;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
});
|
182
|
+
if (historyEvents.length > 0) {
|
183
|
+
addEventsToHistory(historyEvents);
|
184
|
+
}
|
185
|
+
// checkboxes = Array.from(document.querySelectorAll('#session-events input[type="checkbox"]')); // Update checkboxes array after new events
|
186
|
+
} catch (error) {
|
187
|
+
console.error("Error fetching events:", error);
|
188
|
+
} finally {
|
189
|
+
isFetching = false;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
function addEventsToHistory(events) {
|
194
|
+
const container = document.getElementById('initial-events');
|
195
|
+
const fragment = document.createDocumentFragment();
|
196
|
+
|
197
|
+
events.forEach(event => {
|
198
|
+
displayedEventIds.add(event.id);
|
199
|
+
const div = document.createElement('div');
|
200
|
+
const shadowRoot = div.attachShadow({ mode: 'open' });
|
201
|
+
|
202
|
+
const wrapper = document.createElement('div');
|
203
|
+
wrapper.className = 'textline';
|
204
|
+
wrapper.innerHTML = `<p>${event.text}</p>
|
205
|
+
<em class="clock-icon">${event.time.replace(' GMT', '')}</em>
|
206
|
+
`;
|
207
|
+
|
208
|
+
const style = document.createElement('style');
|
209
|
+
style.textContent = mainStyle.innerHTML;
|
210
|
+
shadowRoot.appendChild(style);
|
211
|
+
shadowRoot.appendChild(wrapper);
|
212
|
+
|
213
|
+
fragment.appendChild(div);
|
214
|
+
});
|
215
|
+
|
216
|
+
container.appendChild(fragment);
|
217
|
+
window.scrollTo({
|
218
|
+
top: document.documentElement.scrollHeight,
|
219
|
+
});
|
220
|
+
}
|
221
|
+
|
222
|
+
|
223
|
+
function addNewEvent(event) {
|
224
|
+
displayedEventIds.add(event.id);
|
225
|
+
const container = document.getElementById('session-events');
|
226
|
+
const div = document.createElement('div');
|
227
|
+
// div.className = 'textline';
|
228
|
+
|
229
|
+
const shadowRoot = div.attachShadow({ mode: 'open' }); // 'open' allows access from the main DOM
|
230
|
+
|
231
|
+
const wrapper = document.createElement('div');
|
232
|
+
wrapper.className = 'textline';
|
233
|
+
wrapper.innerHTML = `
|
234
|
+
<input type="checkbox"
|
235
|
+
class="multi-line-checkbox"
|
236
|
+
id="multi-line-checkbox-${event.id}"
|
237
|
+
${event.checked ? 'checked' : ''}
|
238
|
+
aria-label="Mark item"
|
239
|
+
data-event-id="${event.id}"
|
240
|
+
onchange="toggleCheckbox('${event.id}', this.checked)">
|
241
|
+
<p id="textline-${event.id}" contenteditable="false" ondblclick="this.contentEditable = this.contentEditable === 'true' ? 'false' : 'true'; if (this.contentEditable === 'true') this.focus();">${event.text}</p>
|
242
|
+
<div class="textline-buttons">
|
243
|
+
<button onclick="buttonClick('${event.id}', 'Screenshot')" title="Screenshot" style="background-color: #333; color: #fff; border: 1px solid #555; padding: 6px 10px; font-size: 10px; border-radius: 4px; cursor: pointer; transition: background-color 0.3s;">
|
244
|
+
📷
|
245
|
+
</button>
|
246
|
+
<button onclick="buttonClick('${event.id}', 'Audio')" title="Audio" style="background-color: #333; color: #fff; border: 1px solid #555; padding: 6px 10px; font-size: 10px; border-radius: 4px; cursor: pointer; transition: background-color 0.3s;">
|
247
|
+
🔊
|
248
|
+
</button>
|
249
|
+
</div>
|
250
|
+
`;
|
251
|
+
|
252
|
+
// Apply your component's styles within the shadow DOM
|
253
|
+
const style = document.createElement('style');
|
254
|
+
style.textContent = mainStyle.innerHTML;
|
255
|
+
shadowRoot.appendChild(style);
|
256
|
+
shadowRoot.appendChild(wrapper);
|
257
|
+
|
258
|
+
let checkbox = shadowRoot.querySelector('.multi-line-checkbox')
|
259
|
+
checkboxes.push(checkbox);
|
260
|
+
checkboxMap[event.id] = checkbox; // Store the checkbox in the map for easy access
|
261
|
+
|
262
|
+
let textline = shadowRoot.querySelector('#textline-' + event.id);
|
263
|
+
textLines.push(textline);
|
264
|
+
textLineMap[event.id] = textline; // Store the textline in the map for easy access
|
265
|
+
|
266
|
+
|
267
|
+
container.appendChild(div);
|
268
|
+
window.scrollTo({
|
269
|
+
top: document.documentElement.scrollHeight,
|
270
|
+
});
|
271
|
+
}
|
272
|
+
|
273
|
+
function buttonClick(id, action) {
|
274
|
+
console.log(id);
|
275
|
+
const endpoint = action === 'Screenshot' ? '/get-screenshot' : '/play-audio';
|
276
|
+
fetch(endpoint, {
|
277
|
+
method: 'POST',
|
278
|
+
headers: { 'Content-Type': 'application/json' },
|
279
|
+
body: JSON.stringify({ id })
|
280
|
+
})
|
281
|
+
.then(response => {
|
282
|
+
if (!response.ok) {
|
283
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
284
|
+
}
|
285
|
+
return response.json();
|
286
|
+
})
|
287
|
+
.then(data => {
|
288
|
+
console.log(`${action} action completed for event ID: ${id}`, data);
|
289
|
+
})
|
290
|
+
.catch(error => {
|
291
|
+
console.error(`Error performing ${action} action for event ID: ${id}`, error);
|
292
|
+
});
|
293
|
+
}
|
294
|
+
|
295
|
+
function textDoubleClicked(id) {
|
296
|
+
const textElement = textLineMap[id];
|
297
|
+
console.log(textElement);
|
298
|
+
textElement.contenteditable = textElement.contenteditable === "true" ? "false" : "true";
|
299
|
+
}
|
300
|
+
|
301
|
+
async function toggleCheckbox(id, checked) {
|
302
|
+
try {
|
303
|
+
checkboxes_being_updated.add(id);
|
304
|
+
const res = await fetch('/update_checkbox', {
|
305
|
+
method: 'POST',
|
306
|
+
headers: { 'Content-Type': 'application/json' },
|
307
|
+
body: JSON.stringify({ id })
|
308
|
+
});
|
309
|
+
checkboxes_being_updated.delete(id);
|
310
|
+
if (!res.ok) {
|
311
|
+
throw new Error(`HTTP error! Status: ${res.status}`);
|
312
|
+
}
|
313
|
+
} catch (error) {
|
314
|
+
console.error("Error updating checkbox:", error);
|
315
|
+
}
|
316
|
+
}
|
317
|
+
|
318
|
+
function handleMouseDown(e) {
|
319
|
+
if (e.target.type === 'checkbox') {
|
320
|
+
newCheckboxState = !e.target.checked;
|
321
|
+
isDragging = true;
|
322
|
+
dragStartCheckbox = e.target;
|
323
|
+
hoveredCheckboxes.add(e.target)
|
324
|
+
}
|
325
|
+
}
|
326
|
+
|
327
|
+
function handleMouseUp(e) {
|
328
|
+
if (e.target === dragStartCheckbox) {
|
329
|
+
isDragging = false;
|
330
|
+
dragStartCheckbox = null;
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
if (isDragging) {
|
334
|
+
isDragging = false;
|
335
|
+
|
336
|
+
hoveredCheckboxes.forEach(checkbox => {
|
337
|
+
checkbox.checked = newCheckboxState; // Set all hovered checkboxes to the new state
|
338
|
+
const eventId = checkbox.dataset.eventId;
|
339
|
+
toggleCheckbox(eventId, newCheckboxState);
|
340
|
+
});
|
341
|
+
isDragging = false;
|
342
|
+
dragStartCheckbox = null;
|
343
|
+
}
|
344
|
+
|
345
|
+
}
|
346
|
+
|
347
|
+
function handleMouseOver(e) {
|
348
|
+
if (!isDragging || e.target.type !== 'checkbox' || e.target === dragStartCheckbox) {
|
349
|
+
return;
|
350
|
+
}
|
351
|
+
e.preventDefault(); // Prevent text selection during drag
|
352
|
+
if (dragStartCheckbox) {
|
353
|
+
hoveredCheckboxes.add(e.target);
|
354
|
+
}
|
355
|
+
}
|
356
|
+
|
357
|
+
function handleCheckboxClick(e) {
|
358
|
+
if (!e.shiftKey) {
|
359
|
+
lastChecked = e.target;
|
360
|
+
return;
|
361
|
+
}
|
362
|
+
|
363
|
+
if (!lastChecked) return;
|
364
|
+
|
365
|
+
let inBetween = false;
|
366
|
+
checkboxes.forEach(checkbox => {
|
367
|
+
if (checkbox === e.target || checkbox === lastChecked) {
|
368
|
+
inBetween = !inBetween;
|
369
|
+
}
|
370
|
+
|
371
|
+
if (inBetween) {
|
372
|
+
checkbox.checked = lastChecked.checked;
|
373
|
+
const eventId = checkbox.dataset.eventId;
|
374
|
+
toggleCheckbox(eventId, lastChecked.checked);
|
375
|
+
}
|
376
|
+
});
|
377
|
+
|
378
|
+
lastChecked = e.target;
|
379
|
+
}
|
380
|
+
|
381
|
+
function deleteHistory(e) {
|
382
|
+
e.preventDefault();
|
383
|
+
if (confirm("Are you sure you want to delete the history? This action cannot be undone.")) {
|
384
|
+
fetch('/clear_history', {
|
385
|
+
method: 'POST',
|
386
|
+
headers: { 'Content-Type': 'application/json' }
|
387
|
+
})
|
388
|
+
.then(response => {
|
389
|
+
if (!response.ok) {
|
390
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
391
|
+
}
|
392
|
+
// Clear the displayed events
|
393
|
+
displayedEventIds.clear();
|
394
|
+
document.getElementById('initial-events').innerHTML = '';
|
395
|
+
document.getElementById('session-events').innerHTML = '';
|
396
|
+
document.getElementById('initial-events-separator').style.display = 'none';
|
397
|
+
})
|
398
|
+
.catch(error => {
|
399
|
+
console.error("Error deleting history:", error);
|
400
|
+
});
|
401
|
+
}
|
402
|
+
}
|
403
|
+
|
404
|
+
document.addEventListener('mousedown', handleMouseDown);
|
405
|
+
document.addEventListener('mouseup', handleMouseUp);
|
406
|
+
document.addEventListener('mouseover', handleMouseOver);
|
407
|
+
document.addEventListener('click', handleCheckboxClick);
|
408
|
+
deleteHistoryButton.addEventListener('click', deleteHistory);
|
409
|
+
|
410
|
+
const websocketURL = 'ws://localhost:' + websocketPort;
|
411
|
+
let websocket = {};
|
412
|
+
let reconnectInterval = 1000; // Time in milliseconds to wait before attempting to reconnect
|
413
|
+
|
414
|
+
const connectWebSocket = () => {
|
415
|
+
if (websocket && websocket.readyState === WebSocket.OPEN) {
|
416
|
+
console.log('WebSocket already open, no need to reconnect.');
|
417
|
+
return;
|
418
|
+
}
|
419
|
+
if (websocket && websocket.readyState === WebSocket.CONNECTING) {
|
420
|
+
console.log('WebSocket is currently connecting, waiting...');
|
421
|
+
return;
|
422
|
+
}
|
423
|
+
|
424
|
+
websocket = new WebSocket(websocketURL);
|
425
|
+
|
426
|
+
websocket.onopen = (event) => {
|
427
|
+
console.log('WebSocket connection opened');
|
428
|
+
websocket.send(JSON.stringify({ type: 'initial_data_request' }));
|
429
|
+
};
|
430
|
+
|
431
|
+
websocket.onmessage = (event) => {
|
432
|
+
const data = JSON.parse(event.data);
|
433
|
+
console.log('Received message:', data);
|
434
|
+
if (data.event === 'text_received') {
|
435
|
+
console.log("Adding new event:", data.data);
|
436
|
+
addNewEvent(data.data);
|
437
|
+
} else {
|
438
|
+
console.log('Other message:', data);
|
439
|
+
}
|
440
|
+
};
|
441
|
+
|
442
|
+
websocket.onclose = (event) => {
|
443
|
+
console.log(`WebSocket connection closed. Attempting to reconnect in ${reconnectInterval / 1000} seconds...`);
|
444
|
+
// Only attempt to reconnect if the current websocket object is the one that closed
|
445
|
+
if (websocket === event.target) {
|
446
|
+
// Clear the current websocket reference to allow for a new connection
|
447
|
+
websocket = null;
|
448
|
+
setTimeout(connectWebSocket, reconnectInterval);
|
449
|
+
}
|
450
|
+
};
|
451
|
+
|
452
|
+
websocket.onerror = (error) => {
|
453
|
+
console.error('WebSocket error:', error);
|
454
|
+
// Optionally attempt to reconnect on error as well, ensuring we don't have an active connection
|
455
|
+
if (websocket === error.target || websocket === null) {
|
456
|
+
console.log(`Attempting to reconnect in ${reconnectInterval / 1000} seconds...`);
|
457
|
+
// Clear the current websocket reference
|
458
|
+
websocket = null;
|
459
|
+
setTimeout(connectWebSocket, reconnectInterval);
|
460
|
+
}
|
461
|
+
};
|
462
|
+
return websocket;
|
463
|
+
};
|
464
|
+
|
465
|
+
// connectWebSocket();
|
466
|
+
|
467
|
+
|
468
|
+
fetchEvents();
|
469
|
+
|
470
|
+
console.log("Initial load, fetching events and starting interval...");
|
471
|
+
fetchEvents();
|
472
|
+
intervalId = setInterval(async () => {
|
473
|
+
if (isTabActive) {
|
474
|
+
await fetchEvents();
|
475
|
+
}
|
476
|
+
}, fetchInterval);
|
477
|
+
|
478
|
+
window.scrollTo({
|
479
|
+
top: document.documentElement.scrollHeight,
|
480
|
+
});
|
481
|
+
</script>
|
482
|
+
</body>
|
483
|
+
</html>
|