GameSentenceMiner 2.18.14__py3-none-any.whl → 2.18.16__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/anki.py +8 -53
- GameSentenceMiner/obs.py +1 -2
- GameSentenceMiner/ui/anki_confirmation.py +16 -2
- GameSentenceMiner/util/db.py +11 -7
- GameSentenceMiner/util/games_table.py +320 -0
- GameSentenceMiner/vad.py +3 -3
- GameSentenceMiner/web/anki_api_endpoints.py +506 -0
- GameSentenceMiner/web/database_api.py +239 -117
- GameSentenceMiner/web/static/css/loading-skeleton.css +41 -0
- GameSentenceMiner/web/static/css/search.css +54 -0
- GameSentenceMiner/web/static/css/stats.css +76 -0
- GameSentenceMiner/web/static/js/anki_stats.js +304 -50
- GameSentenceMiner/web/static/js/database.js +44 -7
- GameSentenceMiner/web/static/js/heatmap.js +326 -0
- GameSentenceMiner/web/static/js/overview.js +20 -224
- GameSentenceMiner/web/static/js/search.js +190 -23
- GameSentenceMiner/web/static/js/stats.js +371 -1
- GameSentenceMiner/web/stats.py +188 -0
- GameSentenceMiner/web/templates/anki_stats.html +145 -58
- GameSentenceMiner/web/templates/components/date-range.html +19 -0
- GameSentenceMiner/web/templates/components/html-head.html +45 -0
- GameSentenceMiner/web/templates/components/js-config.html +37 -0
- GameSentenceMiner/web/templates/components/popups.html +15 -0
- GameSentenceMiner/web/templates/components/settings-modal.html +233 -0
- GameSentenceMiner/web/templates/database.html +13 -3
- GameSentenceMiner/web/templates/goals.html +9 -31
- GameSentenceMiner/web/templates/overview.html +16 -223
- GameSentenceMiner/web/templates/search.html +46 -0
- GameSentenceMiner/web/templates/stats.html +49 -311
- GameSentenceMiner/web/texthooking_page.py +4 -66
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/RECORD +36 -27
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/top_level.txt +0 -0
|
@@ -1,32 +1,10 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<!-- Include Chart.js from a CDN -->
|
|
9
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
10
|
-
|
|
11
|
-
<!-- Include html2canvas for screenshot functionality -->
|
|
12
|
-
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
|
13
|
-
|
|
14
|
-
<!-- Include shared theme styles -->
|
|
15
|
-
{% include 'components/theme-styles.html' %}
|
|
16
|
-
|
|
17
|
-
<!-- Include shared CSS -->
|
|
18
|
-
<link rel="stylesheet" href="/static/css/shared.css">
|
|
19
|
-
|
|
20
|
-
<!-- Include shared dashboard and popup CSS -->
|
|
21
|
-
<link rel="stylesheet" href="/static/css/dashboard-shared.css">
|
|
22
|
-
<link rel="stylesheet" href="/static/css/popups-shared.css">
|
|
23
|
-
|
|
24
|
-
<!-- Include stats-specific CSS -->
|
|
25
|
-
<link rel="stylesheet" href="/static/css/stats.css">
|
|
26
|
-
|
|
27
|
-
<!-- Include shared kanji grid CSS -->
|
|
28
|
-
<link rel="stylesheet" href="/static/css/kanji-grid.css">
|
|
29
|
-
</head>
|
|
4
|
+
{% set page_title = 'GSM Dashboard' %}
|
|
5
|
+
{% set page_specific_css = 'stats.css' %}
|
|
6
|
+
{% set include_kanji_grid_css = true %}
|
|
7
|
+
{% include 'components/html-head.html' %}
|
|
30
8
|
|
|
31
9
|
<body>
|
|
32
10
|
|
|
@@ -35,38 +13,40 @@
|
|
|
35
13
|
|
|
36
14
|
<!-- Include shared navigation -->
|
|
37
15
|
{% include 'components/navigation.html' %}
|
|
38
|
-
|
|
16
|
+
|
|
17
|
+
<!-- Include shared date range component -->
|
|
18
|
+
{% include 'components/date-range.html' %}
|
|
19
|
+
|
|
20
|
+
<!-- Include shared popup components -->
|
|
21
|
+
{% include 'components/popups.html' %}
|
|
22
|
+
|
|
23
|
+
<div class="dashboard-card peak-stats">
|
|
39
24
|
<div class="dashboard-card-header">
|
|
40
25
|
<h3 class="dashboard-card-title">
|
|
41
|
-
<span class="dashboard-card-icon"
|
|
42
|
-
|
|
26
|
+
<span class="dashboard-card-icon">🏆</span>
|
|
27
|
+
Peak Statistics
|
|
43
28
|
</h3>
|
|
44
29
|
</div>
|
|
45
|
-
<div class="dashboard-
|
|
46
|
-
<div class="dashboard-
|
|
47
|
-
<
|
|
48
|
-
<
|
|
30
|
+
<div class="dashboard-stats-grid">
|
|
31
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Maximum characters read in a single day">
|
|
32
|
+
<span class="dashboard-stat-value" id="maxDailyChars">-</span>
|
|
33
|
+
<span class="dashboard-stat-label">Most Chars/Day</span>
|
|
49
34
|
</div>
|
|
50
|
-
<div class="dashboard-
|
|
51
|
-
<
|
|
52
|
-
<
|
|
35
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Maximum hours studied in a single day">
|
|
36
|
+
<span class="dashboard-stat-value" id="maxDailyHours">-</span>
|
|
37
|
+
<span class="dashboard-stat-label">Most Hours/Day</span>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Longest continuous reading session">
|
|
40
|
+
<span class="dashboard-stat-value" id="longestSession">-</span>
|
|
41
|
+
<span class="dashboard-stat-label">Longest Session</span>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Maximum characters read in a single session">
|
|
44
|
+
<span class="dashboard-stat-value" id="maxSessionChars">-</span>
|
|
45
|
+
<span class="dashboard-stat-label">Most Chars/Session</span>
|
|
53
46
|
</div>
|
|
54
47
|
</div>
|
|
55
48
|
</div>
|
|
56
|
-
<
|
|
57
|
-
<div class="dashboard-popup-content">
|
|
58
|
-
<div class="dashboard-popup-icon">⚠️</div>
|
|
59
|
-
<div class="dashboard-popup-message">"From" date cannot be later than "To" date.</div>
|
|
60
|
-
<button id="closePopupBtn" class="dashboard-popup-btn">OK</button>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
<div id="noDataPopup" class="no-data-popup hidden">
|
|
64
|
-
<div class="no-data-content">
|
|
65
|
-
<p>No data found for the selected range.</p>
|
|
66
|
-
<button id="closeNoDataPopup">OK</button>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
49
|
+
<br>
|
|
70
50
|
<div class="chart-container">
|
|
71
51
|
<h2>Lines Received Over Time</h2>
|
|
72
52
|
<canvas id="linesChart"></canvas>
|
|
@@ -92,6 +72,16 @@
|
|
|
92
72
|
<canvas id="readingSpeedPerGameChart"></canvas>
|
|
93
73
|
</div>
|
|
94
74
|
|
|
75
|
+
<div class="chart-container">
|
|
76
|
+
<h2>Time of Day Activity Pattern</h2>
|
|
77
|
+
<canvas id="hourlyActivityChart"></canvas>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div class="chart-container">
|
|
81
|
+
<h2>Hourly Reading Speed</h2>
|
|
82
|
+
<canvas id="hourlyReadingSpeedChart"></canvas>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
95
85
|
<div class="chart-container">
|
|
96
86
|
<h2>Kanji Grid</h2>
|
|
97
87
|
<div id="kanjiGridContainer">
|
|
@@ -112,226 +102,8 @@
|
|
|
112
102
|
</div>
|
|
113
103
|
</div>
|
|
114
104
|
|
|
115
|
-
<!--
|
|
116
|
-
|
|
117
|
-
<div class="modal-content">
|
|
118
|
-
<div class="modal-header">
|
|
119
|
-
<h3>Statistics Settings</h3>
|
|
120
|
-
<span class="close-btn" id="closeSettingsModal">×</span>
|
|
121
|
-
</div>
|
|
122
|
-
<div class="modal-body">
|
|
123
|
-
<p style="color: var(--text-secondary); margin-bottom: 20px;">
|
|
124
|
-
Configure how reading time and sessions are calculated for your statistics.
|
|
125
|
-
</p>
|
|
126
|
-
<form id="settingsForm">
|
|
127
|
-
<!-- <div style="margin-bottom: 20px;">
|
|
128
|
-
<label for="timezone-select"
|
|
129
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
130
|
-
Timezone
|
|
131
|
-
</label>
|
|
132
|
-
<div style="display: flex; gap: 8px;">
|
|
133
|
-
<select id="timezone-select" name="timezone"
|
|
134
|
-
style="flex-grow: 1; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;">
|
|
135
|
-
</select>
|
|
136
|
-
<button id="set-local-timezone-btn"
|
|
137
|
-
style="padding: 10px; border: none; border-radius: 5px; background: var(--primary-color); color: white; font-size: 14px; cursor: pointer;">
|
|
138
|
-
Set to Local
|
|
139
|
-
</button>
|
|
140
|
-
</div>
|
|
141
|
-
<small style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
142
|
-
Select the timezone to base your statistics on
|
|
143
|
-
</small>
|
|
144
|
-
</div> -->
|
|
145
|
-
|
|
146
|
-
<div style="margin-bottom: 20px;">
|
|
147
|
-
<label for="afkTimer"
|
|
148
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
149
|
-
AFK Timer (seconds)
|
|
150
|
-
</label>
|
|
151
|
-
<input type="number" id="afkTimer" name="afk_timer_seconds"
|
|
152
|
-
style="padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
153
|
-
placeholder="120">
|
|
154
|
-
<small
|
|
155
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
156
|
-
Maximum time between activities that still counts as active reading
|
|
157
|
-
</small>
|
|
158
|
-
</div>
|
|
159
|
-
|
|
160
|
-
<div style="margin-bottom: 20px;">
|
|
161
|
-
<label for="sessionGap"
|
|
162
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
163
|
-
Session Gap (seconds)
|
|
164
|
-
</label>
|
|
165
|
-
<input type="number" id="sessionGap" name="session_gap_seconds"
|
|
166
|
-
style="padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
167
|
-
placeholder="3600">
|
|
168
|
-
<small
|
|
169
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
170
|
-
Time gap that triggers a new reading session
|
|
171
|
-
</small>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<div style="margin-bottom: 20px;">
|
|
175
|
-
<label for="streakRequirement"
|
|
176
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
177
|
-
Streak Requirement (hours)
|
|
178
|
-
</label>
|
|
179
|
-
<input type="number" id="streakRequirement" name="streak_requirement_hours" min="0.01"
|
|
180
|
-
max="24" step="0.01"
|
|
181
|
-
style="padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
182
|
-
placeholder="1.0">
|
|
183
|
-
<small
|
|
184
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
185
|
-
Minimum hours of reading activity required to maintain streak (0.01-24 hours)
|
|
186
|
-
</small>
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<!-- Reading Goals Section -->
|
|
190
|
-
<div style="margin-bottom: 20px; padding-top: 20px; border-top: 1px solid var(--border-color);">
|
|
191
|
-
<label
|
|
192
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
193
|
-
Reading Goals Configuration
|
|
194
|
-
</label>
|
|
195
|
-
<p style="color: var(--text-secondary); margin-bottom: 20px; font-size: 14px;">
|
|
196
|
-
Set your long-term reading targets for tracking progress and projections.
|
|
197
|
-
</p>
|
|
198
|
-
|
|
199
|
-
<div style="margin-bottom: 15px;">
|
|
200
|
-
<label for="readingHoursTarget"
|
|
201
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
202
|
-
Reading Hours Target
|
|
203
|
-
</label>
|
|
204
|
-
<input type="number" id="readingHoursTarget" name="reading_hours_target" min="1"
|
|
205
|
-
max="10000"
|
|
206
|
-
style="padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
207
|
-
placeholder="1500">
|
|
208
|
-
<small
|
|
209
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
210
|
-
Total reading hours goal (1-10,000 hours) - Default: 1500 hours based on TMW N1
|
|
211
|
-
achievement
|
|
212
|
-
</small>
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<div style="margin-bottom: 15px;">
|
|
216
|
-
<label for="characterCountTarget"
|
|
217
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
218
|
-
Character Count Target
|
|
219
|
-
</label>
|
|
220
|
-
<input type="number" id="characterCountTarget" name="character_count_target" min="1000"
|
|
221
|
-
max="1000000000"
|
|
222
|
-
style="padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
223
|
-
placeholder="25000000">
|
|
224
|
-
<small
|
|
225
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
226
|
-
Total characters read goal (1,000-1,000,000,000) - Default: 25 million characters
|
|
227
|
-
</small>
|
|
228
|
-
</div>
|
|
229
|
-
|
|
230
|
-
<div style="margin-bottom: 15px;">
|
|
231
|
-
<label for="readingHoursTargetDate"
|
|
232
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
233
|
-
Reading Hours Target Date
|
|
234
|
-
</label>
|
|
235
|
-
<input type="date" id="readingHoursTargetDate" name="reading_hours_target_date"
|
|
236
|
-
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
237
|
-
data-date-format="yyyy-mm-dd">
|
|
238
|
-
<small
|
|
239
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
240
|
-
Target date to achieve your reading hours goal
|
|
241
|
-
</small>
|
|
242
|
-
</div>
|
|
243
|
-
|
|
244
|
-
<div style="margin-bottom: 15px;">
|
|
245
|
-
<label for="characterCountTargetDate"
|
|
246
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
247
|
-
Character Count Target Date
|
|
248
|
-
</label>
|
|
249
|
-
<input type="date" id="characterCountTargetDate" name="character_count_target_date"
|
|
250
|
-
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
251
|
-
data-date-format="yyyy-mm-dd">
|
|
252
|
-
<small
|
|
253
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
254
|
-
Target date to achieve your character count goal
|
|
255
|
-
</small>
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
<div style="margin-bottom: 15px;">
|
|
259
|
-
<label for="gamesTarget"
|
|
260
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
261
|
-
Games/Visual Novels Target
|
|
262
|
-
</label>
|
|
263
|
-
<input type="number" id="gamesTarget" name="games_target" min="1" max="1000"
|
|
264
|
-
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
265
|
-
placeholder="100">
|
|
266
|
-
<small
|
|
267
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
268
|
-
Number of games/visual novels to complete (1-1,000) - Default: 100 based on Refold
|
|
269
|
-
standards
|
|
270
|
-
</small>
|
|
271
|
-
</div>
|
|
272
|
-
|
|
273
|
-
<div style="margin-bottom: 15px;">
|
|
274
|
-
<label for="gamesTargetDate"
|
|
275
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
276
|
-
Games/Visual Novels Target Date
|
|
277
|
-
</label>
|
|
278
|
-
<input type="date" id="gamesTargetDate" name="games_target_date"
|
|
279
|
-
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
280
|
-
data-date-format="yyyy-mm-dd">
|
|
281
|
-
<small
|
|
282
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
283
|
-
Target date to achieve your games goal
|
|
284
|
-
</small>
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
|
|
288
|
-
<!-- Import ExStatic Lines Section -->
|
|
289
|
-
<div style="margin-bottom: 20px; padding-top: 20px; border-top: 1px solid var(--border-color);">
|
|
290
|
-
<label
|
|
291
|
-
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
292
|
-
Import ExStatic Lines
|
|
293
|
-
</label>
|
|
294
|
-
<div style="margin-bottom: 10px;">
|
|
295
|
-
<input type="file" id="exstaticFile" accept=".csv"
|
|
296
|
-
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;">
|
|
297
|
-
<small
|
|
298
|
-
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
299
|
-
Select an ExStatic CSV file to import reading data into GSM
|
|
300
|
-
</small>
|
|
301
|
-
</div>
|
|
302
|
-
<button type="button" id="importExstaticBtn"
|
|
303
|
-
style="width: 90%; padding: 10px; background: #666; color: white; border: none; border-radius: 5px; font-size: 14px; cursor: not-allowed; margin-bottom: 10px;"
|
|
304
|
-
disabled>
|
|
305
|
-
Import ExStatic Lines
|
|
306
|
-
</button>
|
|
307
|
-
<div id="importProgress" style="display: none; margin-bottom: 10px;">
|
|
308
|
-
<div
|
|
309
|
-
style="background: var(--bg-tertiary); border-radius: 5px; overflow: hidden; height: 20px; position: relative;">
|
|
310
|
-
<div id="importProgressBar"
|
|
311
|
-
style="background: var(--primary-color); height: 100%; width: 0%; transition: width 0.3s ease;">
|
|
312
|
-
</div>
|
|
313
|
-
<span id="importProgressText"
|
|
314
|
-
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 12px; color: var(--text-primary);">0%</span>
|
|
315
|
-
</div>
|
|
316
|
-
</div>
|
|
317
|
-
<div id="importStatus"
|
|
318
|
-
style="display: none; padding: 10px; border-radius: 5px; font-size: 14px;"></div>
|
|
319
|
-
</div>
|
|
320
|
-
</form>
|
|
321
|
-
|
|
322
|
-
<div id="settingsError"
|
|
323
|
-
style="display: none; background: var(--danger-color); color: white; padding: 10px; border-radius: 5px; margin-bottom: 15px; font-size: 14px;">
|
|
324
|
-
</div>
|
|
325
|
-
<div id="settingsSuccess"
|
|
326
|
-
style="display: none; background: var(--success-color); color: white; padding: 10px; border-radius: 5px; margin-bottom: 15px; font-size: 14px;">
|
|
327
|
-
</div>
|
|
328
|
-
</div>
|
|
329
|
-
<div class="modal-footer">
|
|
330
|
-
<button id="cancelSettingsBtn" class="cancel-btn">Cancel</button>
|
|
331
|
-
<button id="saveSettingsBtn" class="confirm-delete-btn">Save Settings</button>
|
|
332
|
-
</div>
|
|
333
|
-
</div>
|
|
334
|
-
</div>
|
|
105
|
+
<!-- Include shared settings modal -->
|
|
106
|
+
{% include 'components/settings-modal.html' %}
|
|
335
107
|
</div>
|
|
336
108
|
|
|
337
109
|
|
|
@@ -343,7 +115,7 @@
|
|
|
343
115
|
{% set games_target = stats_config.games_target | default(100) %}
|
|
344
116
|
{% set heatmap_year = 'all' %}
|
|
345
117
|
|
|
346
|
-
{% set
|
|
118
|
+
{% set stats_config_vars = {
|
|
347
119
|
'afkTimerSeconds': afk_timer,
|
|
348
120
|
'sessionGapSeconds': session_gap,
|
|
349
121
|
'streakRequirementHours': streak_req,
|
|
@@ -353,46 +125,12 @@
|
|
|
353
125
|
'heatmapDisplayYear': heatmap_year
|
|
354
126
|
} %}
|
|
355
127
|
|
|
356
|
-
<!--
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<script src="/static/js/kanji-grid.js"></script>
|
|
363
|
-
<script src="/static/js/stats.js"></script>
|
|
364
|
-
<!-- <script>
|
|
365
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
366
|
-
const timezoneSelect = document.getElementById('timezone-select');
|
|
367
|
-
const setLocalTimezoneBtn = document.getElementById('set-local-timezone-btn');
|
|
368
|
-
|
|
369
|
-
function populateTimezoneSelect() {
|
|
370
|
-
const timezones = Intl.supportedValuesOf('timeZone');
|
|
371
|
-
const fragment = document.createDocumentFragment();
|
|
372
|
-
|
|
373
|
-
timezones.forEach(tz => {
|
|
374
|
-
const option = document.createElement('option');
|
|
375
|
-
option.value = tz;
|
|
376
|
-
option.textContent = tz.replace(/_/g, ' '); // Improve readability
|
|
377
|
-
fragment.appendChild(option);
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
timezoneSelect.appendChild(fragment);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
function setLocalTimezone() {
|
|
384
|
-
const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
385
|
-
timezoneSelect.value = localTimezone;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
populateTimezoneSelect();
|
|
389
|
-
setLocalTimezone();
|
|
390
|
-
|
|
391
|
-
setLocalTimezoneBtn.addEventListener('click', () => {
|
|
392
|
-
setLocalTimezone();
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
</script> -->
|
|
128
|
+
<!-- Include shared JavaScript configuration -->
|
|
129
|
+
{% set config_vars = stats_config_vars %}
|
|
130
|
+
{% set config_object_name = 'statsConfig' %}
|
|
131
|
+
{% set include_kanji_grid_js = true %}
|
|
132
|
+
{% set page_specific_js = 'stats.js' %}
|
|
133
|
+
{% include 'components/js-config.html' %}
|
|
396
134
|
|
|
397
135
|
</body>
|
|
398
136
|
|
|
@@ -46,6 +46,10 @@ app = flask.Flask(__name__)
|
|
|
46
46
|
# Register database API routes
|
|
47
47
|
register_database_api_routes(app)
|
|
48
48
|
|
|
49
|
+
# Register Anki API routes
|
|
50
|
+
from GameSentenceMiner.web.anki_api_endpoints import register_anki_api_endpoints
|
|
51
|
+
register_anki_api_endpoints(app)
|
|
52
|
+
|
|
49
53
|
# Load data from the JSON file
|
|
50
54
|
def load_data_from_file():
|
|
51
55
|
if os.path.exists(TEXT_REPLACEMENTS_FILE):
|
|
@@ -303,72 +307,6 @@ def goals():
|
|
|
303
307
|
master_config=get_master_config(),
|
|
304
308
|
stats_config=get_stats_config())
|
|
305
309
|
|
|
306
|
-
@app.route('/api/anki_earliest_date')
|
|
307
|
-
def anki_earliest_date():
|
|
308
|
-
"""Returns the timestamp of earliest available card in anki collection."""
|
|
309
|
-
from GameSentenceMiner.anki import get_anki_earliest_date
|
|
310
|
-
earliest_card = get_anki_earliest_date()
|
|
311
|
-
return jsonify({
|
|
312
|
-
"earliest_card": earliest_card
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
@app.route('/api/anki_stats')
|
|
316
|
-
def api_anki_stats():
|
|
317
|
-
"""
|
|
318
|
-
API endpoint to provide Anki vs GSM kanji stats for the frontend.
|
|
319
|
-
Returns:
|
|
320
|
-
{
|
|
321
|
-
"missing_kanji": [ { "kanji": "漢", "frequency": 42 }, ... ],
|
|
322
|
-
"anki_kanji_count": 123,
|
|
323
|
-
"gsm_kanji_count": 456,
|
|
324
|
-
"coverage_percent": 27.0
|
|
325
|
-
}
|
|
326
|
-
"""
|
|
327
|
-
from GameSentenceMiner.anki import get_all_anki_first_field_kanji
|
|
328
|
-
from GameSentenceMiner.web.stats import calculate_kanji_frequency, is_kanji
|
|
329
|
-
from GameSentenceMiner.util.db import GameLinesTable
|
|
330
|
-
|
|
331
|
-
start_timestamp = int(request.args.get('start_timestamp')) if request.args.get('start_timestamp') else None
|
|
332
|
-
end_timestamp = int(request.args.get('end_timestamp')) if request.args.get('end_timestamp') else None
|
|
333
|
-
|
|
334
|
-
# Get GSM lines and calculate kanji frequency
|
|
335
|
-
try:
|
|
336
|
-
all_lines = (
|
|
337
|
-
GameLinesTable.get_lines_filtered_by_timestamp(start_timestamp / 1000, end_timestamp / 1000)
|
|
338
|
-
if start_timestamp is not None and end_timestamp is not None
|
|
339
|
-
else GameLinesTable.all()
|
|
340
|
-
)
|
|
341
|
-
except Exception as e:
|
|
342
|
-
logger.warning(f"Failed to filter lines by timestamp: {e}, fetching all lines instead")
|
|
343
|
-
all_lines = GameLinesTable.all()
|
|
344
|
-
|
|
345
|
-
gsm_kanji_stats = calculate_kanji_frequency(all_lines)
|
|
346
|
-
gsm_kanji_list = gsm_kanji_stats.get("kanji_data", [])
|
|
347
|
-
gsm_kanji_set = set([k["kanji"] for k in gsm_kanji_list])
|
|
348
|
-
|
|
349
|
-
# Get all kanji in Anki (first field only)
|
|
350
|
-
anki_kanji_set = get_all_anki_first_field_kanji(start_timestamp, end_timestamp)
|
|
351
|
-
|
|
352
|
-
# Find missing kanji (in GSM but not in Anki)
|
|
353
|
-
missing_kanji = [
|
|
354
|
-
{"kanji": k["kanji"], "frequency": k["frequency"]}
|
|
355
|
-
for k in gsm_kanji_list if k["kanji"] not in anki_kanji_set
|
|
356
|
-
]
|
|
357
|
-
|
|
358
|
-
# Sort missing kanji by frequency descending
|
|
359
|
-
missing_kanji.sort(key=lambda x: x["frequency"], reverse=True)
|
|
360
|
-
|
|
361
|
-
# Coverage stats
|
|
362
|
-
anki_kanji_count = len(anki_kanji_set)
|
|
363
|
-
gsm_kanji_count = len(gsm_kanji_set)
|
|
364
|
-
coverage_percent = (anki_kanji_count / gsm_kanji_count * 100) if gsm_kanji_count else 0.0
|
|
365
|
-
|
|
366
|
-
return jsonify({
|
|
367
|
-
"missing_kanji": missing_kanji,
|
|
368
|
-
"anki_kanji_count": anki_kanji_count,
|
|
369
|
-
"gsm_kanji_count": gsm_kanji_count,
|
|
370
|
-
"coverage_percent": round(coverage_percent, 1)
|
|
371
|
-
})
|
|
372
310
|
|
|
373
311
|
@app.route('/search')
|
|
374
312
|
def search():
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
GameSentenceMiner/anki.py,sha256=
|
|
2
|
+
GameSentenceMiner/anki.py,sha256=9pjjJrQS7IbA6iTtOaJ0Hs2nBddYXTCZBF5lZ5I4dOs,29593
|
|
3
3
|
GameSentenceMiner/gametext.py,sha256=FBL3kgJ71hCg5Nczuo9dAEi_sLGdVIGgvc62bT5KhCc,10691
|
|
4
4
|
GameSentenceMiner/gsm.py,sha256=0hEpEBDbI9FtiKtHeyrSLKV1nys-mKTKfxLY0Dk7mOQ,36387
|
|
5
|
-
GameSentenceMiner/obs.py,sha256=
|
|
6
|
-
GameSentenceMiner/vad.py,sha256=
|
|
5
|
+
GameSentenceMiner/obs.py,sha256=PtO_zB8zhaBxm_Vp8ggf2JmYAJ72cclBLo0kPuUBIoc,36766
|
|
6
|
+
GameSentenceMiner/vad.py,sha256=jT0pNfoKeoqSAveK9Cl1j9RVKkakeHvoohAge_D3tnU,21275
|
|
7
7
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
GameSentenceMiner/ai/ai_prompting.py,sha256=mq9Odv_FpohXagU-OoSZbLWttdrEl1M1NiqnodeUpD8,29126
|
|
9
9
|
GameSentenceMiner/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -36,16 +36,17 @@ GameSentenceMiner/tools/furigana_filter_preview.py,sha256=DAT2-j6vSDHr9ufk6PiaLi
|
|
|
36
36
|
GameSentenceMiner/tools/ss_selector.py,sha256=ob2oJdiYreDMMau7CvsglpnhZ1CDnJqop3lV54-PjRo,4782
|
|
37
37
|
GameSentenceMiner/tools/window_transparency.py,sha256=GtbxbmZg0-UYPXhfHff-7IKZyY2DKe4B9GdyovfmpeM,8166
|
|
38
38
|
GameSentenceMiner/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
-
GameSentenceMiner/ui/anki_confirmation.py,sha256=
|
|
39
|
+
GameSentenceMiner/ui/anki_confirmation.py,sha256=krrT3q3anTtXNTPHz5ahXSd4genEnEvS07v1JYftBFg,15174
|
|
40
40
|
GameSentenceMiner/ui/config_gui.py,sha256=pCZK7-PyllrNc7QmnT4MQ2rADkSC8y7YJcwz8UqjP48,155072
|
|
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
45
|
GameSentenceMiner/util/configuration.py,sha256=8cXpeUJ4hOr8Qd4JPAx1qn_phBIFuKR5D-PybThu-Qk,48233
|
|
46
|
-
GameSentenceMiner/util/db.py,sha256=
|
|
46
|
+
GameSentenceMiner/util/db.py,sha256=CneZuFGIH6fosHblly4lcrWfU0Qjj5l0coxJy7m1igw,32237
|
|
47
47
|
GameSentenceMiner/util/electron_config.py,sha256=KfeJToeFFVw0IR5MKa-gBzpzaGrU-lyJbR9z-sDEHYU,8767
|
|
48
48
|
GameSentenceMiner/util/ffmpeg.py,sha256=cAzztfY36Xf2WvsJDjavoiMOvA9ac2GVdCrSB4LzHk4,29007
|
|
49
|
+
GameSentenceMiner/util/games_table.py,sha256=VM68MAsdyE6tpdwM4bDSk67qioBOvsEO8-TpnRmUnSo,12003
|
|
49
50
|
GameSentenceMiner/util/get_overlay_coords.py,sha256=TJz3iVimiwhRLwkYNB1uOZnDR4BEWWUWYjoJEe7uSQs,25160
|
|
50
51
|
GameSentenceMiner/util/gsm_utils.py,sha256=mASECTmN10c2yPL4NEfLg0Y0YWwFso1i6r_hhJPR3MY,10974
|
|
51
52
|
GameSentenceMiner/util/model.py,sha256=R-_RYTYLSDNgBoVTPuPBcIHeOznIqi_vBzQ7VQ20WYk,6727
|
|
@@ -61,12 +62,13 @@ GameSentenceMiner/util/downloader/oneocr_dl.py,sha256=l3s9Z-x1b57GX048o5h-MVv0UT
|
|
|
61
62
|
GameSentenceMiner/util/win10toast/__init__.py,sha256=6TL2w6rzNmpJEp6_v2cAJP_7ExA3UsKzwdM08pNcVfE,5341
|
|
62
63
|
GameSentenceMiner/util/win10toast/__main__.py,sha256=5MYnBcFj8y_6Dyc1kiPd0_FsUuh4yl1cv5wsleU6V4w,668
|
|
63
64
|
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
-
GameSentenceMiner/web/
|
|
65
|
+
GameSentenceMiner/web/anki_api_endpoints.py,sha256=r30OTT3YVfgbF6aJ-EGWZLF-j2D9L63jLkRXMycU0p8,23681
|
|
66
|
+
GameSentenceMiner/web/database_api.py,sha256=GyiMZWiT9q7fzA7D26YYE73DnAj3jCk9KUGT1P349y4,89996
|
|
65
67
|
GameSentenceMiner/web/events.py,sha256=6Vyz5c9MdpMIa7Zqljqhap2XFQnAVYJ0CdQV64TSZsA,5119
|
|
66
68
|
GameSentenceMiner/web/gsm_websocket.py,sha256=B0VKpxmsRu0WRh5nFWlpDPBQ6-K2ed7TEIa0O6YWeoo,4166
|
|
67
69
|
GameSentenceMiner/web/service.py,sha256=6cgUmDgtp3ZKzuPFszowjPoq-BDtC1bS3ux6sykeaqo,6662
|
|
68
|
-
GameSentenceMiner/web/stats.py,sha256=
|
|
69
|
-
GameSentenceMiner/web/texthooking_page.py,sha256=
|
|
70
|
+
GameSentenceMiner/web/stats.py,sha256=LYMhekifcQo-cbfy2--b6vycKcu8RAoTnQA4TefcS6U,29037
|
|
71
|
+
GameSentenceMiner/web/texthooking_page.py,sha256=oXu_o1B4LlxVEBa1MPC996pxQrAysGkFXz9GTTUYKfk,13658
|
|
70
72
|
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
73
|
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
|
72
74
|
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
|
@@ -78,28 +80,35 @@ GameSentenceMiner/web/static/web-app-manifest-192x192.png,sha256=EfSNnBmsSaLfESb
|
|
|
78
80
|
GameSentenceMiner/web/static/web-app-manifest-512x512.png,sha256=wyqgCWCrLEUxSRXmaA3iJEESd-vM-ZmlTtZFBY4V8Pk,230819
|
|
79
81
|
GameSentenceMiner/web/static/css/dashboard-shared.css,sha256=qWE6OXcMyVJrCd-UO2jQEq-6sPkJJDA4rJsrpfeodMU,5392
|
|
80
82
|
GameSentenceMiner/web/static/css/kanji-grid.css,sha256=NzJg0Y85mMn4y0Ri5PPm7ATyIgfwGhTHDETQGogzeFM,4328
|
|
83
|
+
GameSentenceMiner/web/static/css/loading-skeleton.css,sha256=4DHa8AdnMvxpA8nH86m8abmm8oWkVfZaNECSl3g2iZk,855
|
|
81
84
|
GameSentenceMiner/web/static/css/overview.css,sha256=FW1ZKLbMRvCm2do0Z5dfzA4sYLQkCTJuLO77aUiJIYU,16313
|
|
82
85
|
GameSentenceMiner/web/static/css/popups-shared.css,sha256=OMbDk6rF5spkFp2Zk3CkkE84Sl4RP4H4h-AhA8lCjhM,2393
|
|
83
|
-
GameSentenceMiner/web/static/css/search.css,sha256=
|
|
86
|
+
GameSentenceMiner/web/static/css/search.css,sha256=30O89k05YkvFR_CMVTwKYh4W9Mqrvh05zHxZuqEz7eM,1182
|
|
84
87
|
GameSentenceMiner/web/static/css/shared.css,sha256=qIah6fFXr7ckRxnHSMfT79qu_tJ67fN-fCcDpU4exHA,19589
|
|
85
|
-
GameSentenceMiner/web/static/css/stats.css,sha256=
|
|
86
|
-
GameSentenceMiner/web/static/js/anki_stats.js,sha256=
|
|
87
|
-
GameSentenceMiner/web/static/js/database.js,sha256=
|
|
88
|
+
GameSentenceMiner/web/static/css/stats.css,sha256=3K9M8qgFJzkU6-xiXRJXd85krK4desi7R8BpxIfHvUU,18093
|
|
89
|
+
GameSentenceMiner/web/static/js/anki_stats.js,sha256=WlfWDvVROSk13g2up9R29Tc8eI_ctsRmzTtLE5v_PxE,18231
|
|
90
|
+
GameSentenceMiner/web/static/js/database.js,sha256=kM5hDl0merhKjbKQhWklLGi1L_O1_tJbkqFXxRTZxe4,33202
|
|
88
91
|
GameSentenceMiner/web/static/js/goals.js,sha256=PaJNS1jR1pIpBxYrI8Gog6XFQNPrnbaNWZ1QX7JVlAo,30938
|
|
92
|
+
GameSentenceMiner/web/static/js/heatmap.js,sha256=9E4SPGxjWX5-EWbXtiKFzNLGY3LtpbUmfmeATcrYRDU,14704
|
|
89
93
|
GameSentenceMiner/web/static/js/kanji-grid.js,sha256=k9y25X4TvFYi2CEO7cusrcFVSQRBFWAT1LQ3zJhewYc,16365
|
|
90
|
-
GameSentenceMiner/web/static/js/overview.js,sha256
|
|
91
|
-
GameSentenceMiner/web/static/js/search.js,sha256=
|
|
94
|
+
GameSentenceMiner/web/static/js/overview.js,sha256=-bENoz8GenHkEKdOFaO8WzsXBHOFS7-VaLapW1qRnUY,52400
|
|
95
|
+
GameSentenceMiner/web/static/js/search.js,sha256=QYbIpmBhFNaQ2O7mPN8k9ChSCikIGJvEo-3jOEU2WPM,16158
|
|
92
96
|
GameSentenceMiner/web/static/js/shared.js,sha256=ZNibQkJxdypg93uMhmr_NEgoT5hJfxikzF6RKGz5Wy0,20416
|
|
93
|
-
GameSentenceMiner/web/static/js/stats.js,sha256=
|
|
94
|
-
GameSentenceMiner/web/templates/anki_stats.html,sha256=
|
|
95
|
-
GameSentenceMiner/web/templates/database.html,sha256=
|
|
96
|
-
GameSentenceMiner/web/templates/goals.html,sha256=
|
|
97
|
+
GameSentenceMiner/web/static/js/stats.js,sha256=zPhkdY3RXiQrhPmZyFyh6xwOn3DxQI8Jm6fqbJbjeDk,51322
|
|
98
|
+
GameSentenceMiner/web/templates/anki_stats.html,sha256=ixMg8nT5gXfTWVFG-xa7pppJuzEG2UAOaDhikWOWAK8,18187
|
|
99
|
+
GameSentenceMiner/web/templates/database.html,sha256=5SE7cSYa-ZDVLm0ykb1T11Yd4Bm_E600EWaQi2UWip8,18577
|
|
100
|
+
GameSentenceMiner/web/templates/goals.html,sha256=X5ViEeUT3YnCVM_kofCJ6A0_Wn2TVQQdmBiblZN5Gpo,20909
|
|
97
101
|
GameSentenceMiner/web/templates/index.html,sha256=y1mrlcKWRdwmfBP8B06p1CBk1avAJOr32388nX8YX4A,229074
|
|
98
|
-
GameSentenceMiner/web/templates/overview.html,sha256=
|
|
99
|
-
GameSentenceMiner/web/templates/search.html,sha256=
|
|
100
|
-
GameSentenceMiner/web/templates/stats.html,sha256=
|
|
102
|
+
GameSentenceMiner/web/templates/overview.html,sha256=HkEelQ60aJkt2OwNouqY2TxUF3fzRt85VHOe32C2-TM,13117
|
|
103
|
+
GameSentenceMiner/web/templates/search.html,sha256=34mv69GQXBGq-TdagyZ82QpXH9JYWGOXMDbCfoGUoGI,6150
|
|
104
|
+
GameSentenceMiner/web/templates/stats.html,sha256=RJhWQ1lyOGkYWrqxJNutnJs703IVdCQhBG9Cud0CMPs,5605
|
|
101
105
|
GameSentenceMiner/web/templates/utility.html,sha256=KtqnZUMAYs5XsEdC9Tlsd40NKAVic0mu6sh-ReMDJpU,16940
|
|
106
|
+
GameSentenceMiner/web/templates/components/date-range.html,sha256=kgfsPCJYKbqn8N5mEZTpC8s2aPE6xSrXWEeSQyPfcdE,950
|
|
107
|
+
GameSentenceMiner/web/templates/components/html-head.html,sha256=8gD3iu3YhM3-q6PVfhLZ9L6rdWfbbpKKXY0CSXAitZc,1579
|
|
108
|
+
GameSentenceMiner/web/templates/components/js-config.html,sha256=-ZnbMWGJ7Ck190kqcEIBdjuglSiGUCt307ixztHuo0M,960
|
|
102
109
|
GameSentenceMiner/web/templates/components/navigation.html,sha256=7FGv59-4QocYy3b_BolkPXsp2drwwLjHraL5GUM27b4,1165
|
|
110
|
+
GameSentenceMiner/web/templates/components/popups.html,sha256=hSe3HCp_TA8lEEOxI4ZLCTJvGH7RO8EI1b3ktxDgbls,789
|
|
111
|
+
GameSentenceMiner/web/templates/components/settings-modal.html,sha256=6d47ov5nVlHMFgFugGkq89Z9_Zp_yqmj7YfU0U7q-Y8,15779
|
|
103
112
|
GameSentenceMiner/web/templates/components/theme-styles.html,sha256=hiq3zdJljpRjQO1iUA7gfFKwXebltG-IWW-gnKS4GHA,3439
|
|
104
113
|
GameSentenceMiner/web/templates/components/kanji_grid/basic_kanji_book_bkb_v1_v2.json,sha256=jVf6zp1qCEng0YFZQJsBmHwJyWWgT-Q__bhkFzc9dHo,1868
|
|
105
114
|
GameSentenceMiner/web/templates/components/kanji_grid/duolingo_kanji.json,sha256=0DqxCTtR2D6QxnXMHkr022254_OLRvc2lLSiybxEsJw,6338
|
|
@@ -126,9 +135,9 @@ GameSentenceMiner/web/templates/components/kanji_grid/thousand_character_classic
|
|
|
126
135
|
GameSentenceMiner/web/templates/components/kanji_grid/wanikani_levels.json,sha256=8wjnnaYQqmho6t5tMxrIAc03512A2tYhQh5dfsQnfAM,11372
|
|
127
136
|
GameSentenceMiner/web/templates/components/kanji_grid/words_hk_frequency_list.json,sha256=wRkqZNPzz6DT9OTPHpXwfqW96Qb96stCQNNgOL-ZdKk,17535
|
|
128
137
|
GameSentenceMiner/wip/__init___.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
129
|
-
gamesentenceminer-2.18.
|
|
130
|
-
gamesentenceminer-2.18.
|
|
131
|
-
gamesentenceminer-2.18.
|
|
132
|
-
gamesentenceminer-2.18.
|
|
133
|
-
gamesentenceminer-2.18.
|
|
134
|
-
gamesentenceminer-2.18.
|
|
138
|
+
gamesentenceminer-2.18.16.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
139
|
+
gamesentenceminer-2.18.16.dist-info/METADATA,sha256=X02yygMguMepPkrv_08yYZLA9v_SzhAwbwAfKFHhJ4U,7488
|
|
140
|
+
gamesentenceminer-2.18.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
141
|
+
gamesentenceminer-2.18.16.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
|
142
|
+
gamesentenceminer-2.18.16.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
|
143
|
+
gamesentenceminer-2.18.16.dist-info/RECORD,,
|
|
File without changes
|
{gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{gamesentenceminer-2.18.14.dist-info → gamesentenceminer-2.18.16.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|