GameSentenceMiner 2.16.0__py3-none-any.whl → 2.16.2__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 CHANGED
@@ -790,7 +790,6 @@ async def async_main(reloading=False):
790
790
 
791
791
 
792
792
  def main():
793
- """Main function to run the Game Sentence Miner."""
794
793
  logger.info("Starting GSM")
795
794
  try:
796
795
  asyncio.run(async_main())
@@ -10,9 +10,37 @@ from GameSentenceMiner.util.downloader.Untitled_json import scenes
10
10
  from GameSentenceMiner.util.configuration import get_app_directory, logger
11
11
  from GameSentenceMiner.util.ffmpeg import get_ffmpeg_path, get_ffprobe_path
12
12
  from GameSentenceMiner.obs import get_obs_path
13
+ import tempfile
13
14
 
14
15
  script_dir = os.path.dirname(os.path.abspath(__file__))
15
16
 
17
+ def cleanup_temp_files(func):
18
+ def wrapper(*args, **kwargs):
19
+ temp_files = []
20
+
21
+ # Patch tempfile.NamedTemporaryFile to track created temp files
22
+ orig_named_tempfile = tempfile.NamedTemporaryFile
23
+ def tracked_named_tempfile(*a, **kw):
24
+ tmp = orig_named_tempfile(*a, **kw)
25
+ temp_files.append(tmp.name)
26
+ return tmp
27
+ tempfile.NamedTemporaryFile = tracked_named_tempfile
28
+
29
+ try:
30
+ result = func(*args, **kwargs)
31
+ finally:
32
+ # Restore original NamedTemporaryFile
33
+ tempfile.NamedTemporaryFile = orig_named_tempfile
34
+ # Remove tracked temp files
35
+ for f in temp_files:
36
+ try:
37
+ if os.path.exists(f):
38
+ os.remove(f)
39
+ except Exception:
40
+ pass
41
+ return result
42
+ return wrapper
43
+
16
44
  def copy_obs_settings(src, dest):
17
45
 
18
46
  if os.path.exists(src):
@@ -111,6 +139,9 @@ def download_obs_if_needed():
111
139
  with open(os.path.join(scene_json_path, 'Untitled.json'), 'w') as scene_file:
112
140
  scene_file.write(scenes)
113
141
  logger.info(f"OBS extracted to {obs_path}.")
142
+
143
+ # remove zip
144
+ os.unlink(obs_installer)
114
145
  else:
115
146
  logger.error(f"Please install OBS manually from {obs_installer}")
116
147
 
@@ -118,9 +149,14 @@ def download_ffmpeg_if_needed():
118
149
  ffmpeg_dir = os.path.join(get_app_directory(), 'ffmpeg')
119
150
  ffmpeg_exe_path = get_ffmpeg_path()
120
151
  ffprobe_exe_path = get_ffprobe_path()
121
-
152
+ python_dir = os.path.join(get_app_directory(), 'python')
153
+ ffmpeg_in_python = os.path.join(python_dir, "ffmpeg.exe")
154
+
122
155
  if os.path.exists(ffmpeg_dir) and os.path.exists(ffmpeg_exe_path) and os.path.exists(ffprobe_exe_path):
123
156
  logger.debug(f"FFmpeg already installed at {ffmpeg_dir}.")
157
+ if not os.path.exists(ffmpeg_in_python):
158
+ shutil.copy2(ffmpeg_exe_path, ffmpeg_in_python)
159
+ logger.info(f"Copied ffmpeg.exe to Python folder: {ffmpeg_in_python}")
124
160
  return
125
161
 
126
162
  if os.path.exists(ffmpeg_dir) and (not os.path.exists(ffmpeg_exe_path) or not os.path.exists(ffprobe_exe_path)):
@@ -155,6 +191,13 @@ def download_ffmpeg_if_needed():
155
191
  target = open(os.path.join(ffmpeg_dir, filename), "wb")
156
192
  with source, target:
157
193
  shutil.copyfileobj(source, target)
194
+
195
+ # Copy ffmpeg.exe to the python folder
196
+ if os.path.exists(ffmpeg_exe_path):
197
+ shutil.copy2(ffmpeg_exe_path, ffmpeg_in_python)
198
+ logger.info(f"Copied ffmpeg.exe to Python folder: {ffmpeg_in_python}")
199
+ else:
200
+ logger.warning(f"ffmpeg.exe not found in {ffmpeg_dir}.")
158
201
  logger.info(f"FFmpeg extracted to {ffmpeg_dir}.")
159
202
 
160
203
  def download_ocenaudio_if_needed():
@@ -1,4 +1,4 @@
1
- /* Shared CSS for Game Sentence Miner Web Application */
1
+ /* Shared CSS for GSM Web Application */
2
2
 
3
3
  /* Base Styles */
4
4
  body {
@@ -491,6 +491,70 @@ function escapeRegex(string) {
491
491
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
492
492
  }
493
493
 
494
+ // Screenshot functionality
495
+ function initializeScreenshotButton() {
496
+ const screenshotButton = document.getElementById('screenshotToggle');
497
+
498
+ if (!screenshotButton) {
499
+ return; // Screenshot button not available on this page
500
+ }
501
+
502
+ screenshotButton.addEventListener('click', takeScreenshot);
503
+ }
504
+
505
+ async function takeScreenshot() {
506
+ try {
507
+ // Check if html2canvas is available
508
+ if (typeof html2canvas === 'undefined') {
509
+ console.error('html2canvas library not loaded');
510
+ return;
511
+ }
512
+
513
+ // Generate timestamp for filename
514
+ const now = new Date();
515
+ const timestamp = now.getFullYear() + '-' +
516
+ String(now.getMonth() + 1).padStart(2, '0') + '-' +
517
+ String(now.getDate()).padStart(2, '0') + '_' +
518
+ String(now.getHours()).padStart(2, '0') + '-' +
519
+ String(now.getMinutes()).padStart(2, '0') + '-' +
520
+ String(now.getSeconds()).padStart(2, '0');
521
+
522
+ const filename = `screenshot_${timestamp}.png`;
523
+
524
+ // Capture the entire page
525
+ const canvas = await html2canvas(document.body, {
526
+ useCORS: true,
527
+ allowTaint: true,
528
+ scale: 1,
529
+ scrollX: 0,
530
+ scrollY: 0,
531
+ width: document.body.scrollWidth,
532
+ height: document.body.scrollHeight
533
+ });
534
+
535
+ // Convert canvas to blob
536
+ canvas.toBlob(function(blob) {
537
+ // Create download link
538
+ const link = document.createElement('a');
539
+ link.download = filename;
540
+ link.href = URL.createObjectURL(blob);
541
+
542
+ // Trigger download
543
+ document.body.appendChild(link);
544
+ link.click();
545
+ document.body.removeChild(link);
546
+
547
+ // Clean up the URL object after a short delay to avoid race condition
548
+ setTimeout(function() {
549
+ URL.revokeObjectURL(link.href);
550
+ }, 100);
551
+ }, 'image/png');
552
+
553
+ } catch (error) {
554
+ console.error('Screenshot failed:', error);
555
+ }
556
+ }
557
+
494
558
  // Initialize shared functionality when DOM loads
495
559
  document.addEventListener('DOMContentLoaded', function() {
496
560
  // Initialize theme toggle
@@ -499,6 +563,9 @@ document.addEventListener('DOMContentLoaded', function() {
499
563
  // Initialize modal handlers
500
564
  initializeModalHandlers();
501
565
 
566
+ // Initialize screenshot button
567
+ initializeScreenshotButton();
568
+
502
569
  // Initialize settings manager if settings toggle exists
503
570
  if (document.getElementById('settingsToggle')) {
504
571
  new SettingsManager();
@@ -4,6 +4,10 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Anki vs GSM Kanji Stats</title>
7
+
8
+ <!-- Include html2canvas for screenshot functionality -->
9
+ <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
10
+
7
11
  <!-- Include Chart.js from a CDN -->
8
12
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
13
 
@@ -1,7 +1,7 @@
1
1
  <!-- Navigation Component -->
2
2
  <div class="navigation" style="display: flex; justify-content: center; align-items: center; margin-bottom: 30px; padding: 15px; background: var(--bg-secondary); border-radius: 8px; box-shadow: 0 2px 8px var(--shadow-color); border: 1px solid var(--border-color);">
3
3
  <div style="display: flex; gap: 15px;">
4
- <a href="/" class="nav-link">Home</a>
4
+ <!-- <a href="/" class="nav-link">Home</a> -->
5
5
  <a href="/stats" class="nav-link">Statistics</a>
6
6
  <a href="/search" class="nav-link">Search</a>
7
7
  <a href="/database" class="nav-link">Database Management</a>
@@ -10,6 +10,9 @@
10
10
  <button class="theme-toggle" id="settingsToggle" title="Settings">
11
11
  <span id="settingsIcon">⚙️</span>
12
12
  </button>
13
+ <button class="theme-toggle" id="screenshotToggle" title="Take screenshot">
14
+ <span id="screenshotIcon">📷</span>
15
+ </button>
13
16
  <button class="theme-toggle" id="themeToggle" title="Toggle dark mode">
14
17
  <span id="themeIcon">🌙</span>
15
18
  </button>
@@ -6,6 +6,9 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>GSM Database Management</title>
8
8
 
9
+ <!-- Include html2canvas for screenshot functionality -->
10
+ <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
11
+
9
12
  <!-- Include shared theme styles -->
10
13
  {% include 'components/theme-styles.html' %}
11
14
 
@@ -15,7 +18,7 @@
15
18
  <body>
16
19
 
17
20
  <div class="container">
18
- <h1>Game Sentence Miner - Database Management</h1>
21
+ <h1>GSM - Database Management</h1>
19
22
 
20
23
  <!-- Include shared navigation -->
21
24
  {% include 'components/navigation.html' %}