GameSentenceMiner 2.5.12__py3-none-any.whl → 2.5.14__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 +8 -5
- GameSentenceMiner/communication/websocket.py +9 -0
- GameSentenceMiner/config_gui.py +17 -2
- GameSentenceMiner/configuration.py +4 -3
- GameSentenceMiner/gsm.py +15 -6
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/RECORD +11 -11
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.5.12.dist-info → gamesentenceminer-2.5.14.dist-info}/top_level.txt +0 -0
GameSentenceMiner/anki.py
CHANGED
@@ -32,8 +32,9 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
32
32
|
global audio_in_anki, screenshot_in_anki, prev_screenshot_in_anki
|
33
33
|
update_audio = should_update_audio and (get_config().anki.sentence_audio_field and not
|
34
34
|
last_note.get_field(get_config().anki.sentence_audio_field) or get_config().anki.overwrite_audio)
|
35
|
-
update_picture = (get_config().anki.picture_field and get_config().
|
36
|
-
|
35
|
+
update_picture = (get_config().anki.picture_field and get_config().screenshot.enabled
|
36
|
+
and (get_config().anki.overwrite_picture or not last_note.get_field(get_config().anki.picture_field)))
|
37
|
+
|
37
38
|
|
38
39
|
if not reuse_audio:
|
39
40
|
if update_audio:
|
@@ -54,11 +55,13 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
54
55
|
|
55
56
|
# note = {'id': last_note.noteId, 'fields': {}}
|
56
57
|
|
57
|
-
if update_audio:
|
58
|
+
if update_audio and audio_in_anki:
|
58
59
|
note['fields'][get_config().anki.sentence_audio_field] = audio_html
|
59
60
|
|
60
|
-
if update_picture:
|
61
|
+
if update_picture and screenshot_in_anki:
|
61
62
|
note['fields'][get_config().anki.picture_field] = image_html
|
63
|
+
if not get_config().screenshot.enabled:
|
64
|
+
logger.info("Skipping Adding Screenshot to Anki, Screenshot is disabled in settings")
|
62
65
|
|
63
66
|
if prev_screenshot_in_anki:
|
64
67
|
note['fields'][get_config().anki.previous_image_field] = prev_screenshot_html
|
@@ -82,7 +85,7 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
82
85
|
if get_config().features.open_anki_edit:
|
83
86
|
notification.open_anki_card(last_note.noteId)
|
84
87
|
|
85
|
-
if get_config().audio.external_tool:
|
88
|
+
if get_config().audio.external_tool and get_config().audio.external_tool_enabled and update_audio:
|
86
89
|
open_audio_in_external(f"{get_config().audio.anki_media_collection}/{audio_in_anki}")
|
87
90
|
|
88
91
|
|
@@ -3,6 +3,7 @@ import os.path
|
|
3
3
|
|
4
4
|
import websockets
|
5
5
|
import json
|
6
|
+
from enum import Enum
|
6
7
|
|
7
8
|
from websocket import WebSocket
|
8
9
|
|
@@ -13,6 +14,14 @@ CONFIG_FILE = os.path.join(get_app_directory(), "shared_config.json")
|
|
13
14
|
websocket: WebSocket = None
|
14
15
|
handle_websocket_message = None
|
15
16
|
|
17
|
+
|
18
|
+
class FunctionName(Enum):
|
19
|
+
QUIT = "quit"
|
20
|
+
START = "start"
|
21
|
+
STOP = "stop"
|
22
|
+
QUIT_OBS = "quit_obs"
|
23
|
+
START_OBS = "start_obs"
|
24
|
+
|
16
25
|
async def do_websocket_connection(port):
|
17
26
|
"""
|
18
27
|
Connects to the WebSocket server running in the Electron app.
|
GameSentenceMiner/config_gui.py
CHANGED
@@ -147,6 +147,7 @@ class ConfigApp:
|
|
147
147
|
backfill_audio=self.backfill_audio.get()
|
148
148
|
),
|
149
149
|
screenshot=Screenshot(
|
150
|
+
enabled=self.screenshot_enabled.get(),
|
150
151
|
width=self.screenshot_width.get(),
|
151
152
|
height=self.screenshot_height.get(),
|
152
153
|
quality=self.screenshot_quality.get(),
|
@@ -157,12 +158,14 @@ class ConfigApp:
|
|
157
158
|
use_beginning_of_line_as_screenshot=self.use_beginning_of_line_as_screenshot.get()
|
158
159
|
),
|
159
160
|
audio=Audio(
|
161
|
+
enabled=self.audio_enabled.get(),
|
160
162
|
extension=self.audio_extension.get(),
|
161
163
|
beginning_offset=float(self.beginning_offset.get()),
|
162
164
|
end_offset=float(self.end_offset.get()),
|
163
165
|
ffmpeg_reencode_options=self.ffmpeg_reencode_options.get(),
|
164
166
|
external_tool = self.external_tool.get(),
|
165
167
|
anki_media_collection=self.anki_media_collection.get(),
|
168
|
+
external_tool_enabled=self.external_tool_enabled.get(),
|
166
169
|
),
|
167
170
|
obs=OBS(
|
168
171
|
enabled=self.obs_enabled.get(),
|
@@ -171,7 +174,6 @@ class ConfigApp:
|
|
171
174
|
host=self.obs_host.get(),
|
172
175
|
port=int(self.obs_port.get()),
|
173
176
|
password=self.obs_password.get(),
|
174
|
-
start_buffer=self.obs_start_buffer.get(),
|
175
177
|
get_game_from_scene=self.get_game_from_scene_name.get(),
|
176
178
|
minimum_replay_size=int(self.minimum_replay_size.get())
|
177
179
|
),
|
@@ -679,6 +681,11 @@ class ConfigApp:
|
|
679
681
|
screenshot_frame = ttk.Frame(self.notebook)
|
680
682
|
self.notebook.add(screenshot_frame, text='Screenshot')
|
681
683
|
|
684
|
+
ttk.Label(screenshot_frame, text="Enabled:").grid(row=self.current_row, column=0, sticky='W')
|
685
|
+
self.screenshot_enabled = tk.BooleanVar(value=self.settings.screenshot.enabled)
|
686
|
+
ttk.Checkbutton(screenshot_frame, variable=self.screenshot_enabled).grid(row=self.current_row, column=1, sticky='W')
|
687
|
+
self.add_label_and_increment_row(screenshot_frame, "Enable or disable screenshot processing.", row=self.current_row, column=2)
|
688
|
+
|
682
689
|
ttk.Label(screenshot_frame, text="Width:").grid(row=self.current_row, column=0, sticky='W')
|
683
690
|
self.screenshot_width = ttk.Entry(screenshot_frame)
|
684
691
|
self.screenshot_width.insert(0, str(self.settings.screenshot.width))
|
@@ -737,6 +744,11 @@ class ConfigApp:
|
|
737
744
|
audio_frame = ttk.Frame(self.notebook)
|
738
745
|
self.notebook.add(audio_frame, text='Audio')
|
739
746
|
|
747
|
+
ttk.Label(audio_frame, text="Enabled:").grid(row=self.current_row, column=0, sticky='W')
|
748
|
+
self.audio_enabled = tk.BooleanVar(value=self.settings.audio.enabled)
|
749
|
+
ttk.Checkbutton(audio_frame, variable=self.audio_enabled).grid(row=self.current_row, column=1, sticky='W')
|
750
|
+
self.add_label_and_increment_row(audio_frame, "Enable or disable audio processing.", row=self.current_row, column=2)
|
751
|
+
|
740
752
|
ttk.Label(audio_frame, text="Audio Extension:").grid(row=self.current_row, column=0, sticky='W')
|
741
753
|
self.audio_extension = ttk.Combobox(audio_frame, values=['opus', 'mp3', 'ogg', 'aac', 'm4a'])
|
742
754
|
self.audio_extension.insert(0, self.settings.audio.extension)
|
@@ -777,10 +789,13 @@ class ConfigApp:
|
|
777
789
|
self.external_tool = ttk.Entry(audio_frame)
|
778
790
|
self.external_tool.insert(0, self.settings.audio.external_tool)
|
779
791
|
self.external_tool.grid(row=self.current_row, column=1)
|
792
|
+
ttk.Label(audio_frame, text="Enabled:").grid(row=self.current_row, column=2, sticky='W')
|
793
|
+
self.external_tool_enabled = tk.BooleanVar(value=self.settings.audio.external_tool_enabled)
|
794
|
+
ttk.Checkbutton(audio_frame, variable=self.external_tool_enabled).grid(row=self.current_row, column=3, sticky='W')
|
780
795
|
self.add_label_and_increment_row(audio_frame,
|
781
796
|
"Path to External tool that opens the audio up for manual trimming. I recommend OcenAudio for in-place Editing.",
|
782
797
|
row=self.current_row,
|
783
|
-
column=
|
798
|
+
column=4)
|
784
799
|
|
785
800
|
ttk.Button(audio_frame, text="Install Ocenaudio", command=self.download_and_install_ocen).grid(
|
786
801
|
row=self.current_row, column=0, pady=5)
|
@@ -98,6 +98,7 @@ class Features:
|
|
98
98
|
@dataclass_json
|
99
99
|
@dataclass
|
100
100
|
class Screenshot:
|
101
|
+
enabled: bool = True
|
101
102
|
width: str = 0
|
102
103
|
height: str = 0
|
103
104
|
quality: str = 85
|
@@ -111,12 +112,14 @@ class Screenshot:
|
|
111
112
|
@dataclass_json
|
112
113
|
@dataclass
|
113
114
|
class Audio:
|
115
|
+
enabled: bool = True
|
114
116
|
extension: str = 'opus'
|
115
117
|
beginning_offset: float = 0.0
|
116
118
|
end_offset: float = 0.5
|
117
119
|
ffmpeg_reencode_options: str = ''
|
118
120
|
external_tool: str = ""
|
119
121
|
anki_media_collection: str = ""
|
122
|
+
external_tool_enabled: bool = True
|
120
123
|
|
121
124
|
|
122
125
|
@dataclass_json
|
@@ -309,9 +312,6 @@ class Config:
|
|
309
312
|
self.sync_shared_field(config.hotkeys, profile.hotkeys, "take_screenshot")
|
310
313
|
self.sync_shared_field(config.hotkeys, profile.hotkeys, "open_utility")
|
311
314
|
self.sync_shared_field(config.hotkeys, profile.hotkeys, "play_latest_audio")
|
312
|
-
# self.sync_shared_field(config.advanced, profile.advanced, "audio_player_path")
|
313
|
-
# self.sync_shared_field(config.advanced, profile.advanced, "video_player_path")
|
314
|
-
# self.sync_shared_field(config.advanced, profile.advanced, "show_screenshot_buttons")
|
315
315
|
self.sync_shared_field(config.anki, profile.anki, "url")
|
316
316
|
self.sync_shared_field(config.anki, profile.anki, "sentence_field")
|
317
317
|
self.sync_shared_field(config.anki, profile.anki, "sentence_audio_field")
|
@@ -337,6 +337,7 @@ class Config:
|
|
337
337
|
|
338
338
|
return self
|
339
339
|
|
340
|
+
|
340
341
|
def sync_shared_field(self, config, config2, field_name):
|
341
342
|
try:
|
342
343
|
config_value = getattr(config, field_name, None)
|
GameSentenceMiner/gsm.py
CHANGED
@@ -23,7 +23,8 @@ from GameSentenceMiner import obs
|
|
23
23
|
from GameSentenceMiner import util
|
24
24
|
from GameSentenceMiner.communication import Message
|
25
25
|
from GameSentenceMiner.communication.send import send_restart_signal
|
26
|
-
from GameSentenceMiner.communication.websocket import connect_websocket, register_websocket_message_handler
|
26
|
+
from GameSentenceMiner.communication.websocket import connect_websocket, register_websocket_message_handler, \
|
27
|
+
FunctionName
|
27
28
|
from GameSentenceMiner.configuration import *
|
28
29
|
from GameSentenceMiner.downloader.download_tools import download_obs_if_needed, download_ffmpeg_if_needed
|
29
30
|
from GameSentenceMiner.ffmpeg import get_audio_and_trim, get_video_timings
|
@@ -125,7 +126,7 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
125
126
|
tango = last_note.get_field(get_config().anki.word_field) if last_note else ''
|
126
127
|
get_utility_window().reset_checkboxes()
|
127
128
|
|
128
|
-
if get_config().anki.sentence_audio_field:
|
129
|
+
if get_config().anki.sentence_audio_field and get_config().audio.enabled:
|
129
130
|
logger.debug("Attempting to get audio from video")
|
130
131
|
final_audio_output, should_update_audio, vad_trimmed_audio = VideoToAudioHandler.get_audio(
|
131
132
|
start_line,
|
@@ -135,7 +136,10 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
135
136
|
final_audio_output = ""
|
136
137
|
should_update_audio = False
|
137
138
|
vad_trimmed_audio = ""
|
138
|
-
|
139
|
+
if not get_config().audio.enabled:
|
140
|
+
logger.info("Audio is disabled in config, skipping audio processing!")
|
141
|
+
elif not get_config().anki.sentence_audio_field:
|
142
|
+
logger.info("No SentenceAudio Field in config, skipping audio processing!")
|
139
143
|
if get_config().anki.update_anki and last_note:
|
140
144
|
anki.update_anki_card(last_note, note, audio_path=final_audio_output, video_path=video_path,
|
141
145
|
tango=tango,
|
@@ -442,6 +446,7 @@ def run_tray():
|
|
442
446
|
# proc.wait()
|
443
447
|
|
444
448
|
def close_obs():
|
449
|
+
obs.disconnect_from_obs()
|
445
450
|
if obs.obs_process:
|
446
451
|
try:
|
447
452
|
subprocess.run(["taskkill", "/PID", str(obs.obs_process.pid), "/F"], check=True, capture_output=True, text=True)
|
@@ -550,12 +555,16 @@ def post_init():
|
|
550
555
|
|
551
556
|
util.run_new_thread(do_post_init)
|
552
557
|
|
553
|
-
|
554
558
|
def handle_websocket_message(message: Message):
|
555
|
-
match message.function:
|
556
|
-
case
|
559
|
+
match FunctionName(message.function):
|
560
|
+
case FunctionName.QUIT:
|
557
561
|
cleanup()
|
558
562
|
sys.exit(0)
|
563
|
+
case FunctionName.QUIT_OBS:
|
564
|
+
close_obs()
|
565
|
+
case FunctionName.START_OBS:
|
566
|
+
obs.start_obs()
|
567
|
+
obs.connect_to_obs()
|
559
568
|
case _:
|
560
569
|
logger.debug(f"unknown message from electron websocket: {message.to_json()}")
|
561
570
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=
|
4
|
-
GameSentenceMiner/configuration.py,sha256=
|
2
|
+
GameSentenceMiner/anki.py,sha256=FHm76i7WYEs--szhzZjz0B6DW4JuDQopmjR3RjYBogs,13358
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=WVSN239lyVm5GwKzE1HXiCSCu2CNpkcDm8TGKlTJpMc,62093
|
4
|
+
GameSentenceMiner/configuration.py,sha256=obBhz7aAFkhQAhIqrocv2jRTOqIJ0tFEI_saUCyMAMc,19924
|
5
5
|
GameSentenceMiner/ffmpeg.py,sha256=fzOxrn-a4KqFdUY2oove164CTDOSsdPQtzqRW5f1P7c,12002
|
6
6
|
GameSentenceMiner/gametext.py,sha256=LORVdE2WEo1CDI8gonc7qxrhbS4KFKXFQVKjhlkpLbc,7368
|
7
|
-
GameSentenceMiner/gsm.py,sha256=
|
7
|
+
GameSentenceMiner/gsm.py,sha256=ZdYVJKilDFEGdC3g5V5pjSr4G2JkNNDIt7BQX6yc28A,24456
|
8
8
|
GameSentenceMiner/model.py,sha256=JdnkT4VoPOXmOpRgFdvERZ09c9wLN6tUJxdrKlGZcqo,5305
|
9
9
|
GameSentenceMiner/notification.py,sha256=FY39ChSRK0Y8TQ6lBGsLnpZUFPtFpSy2tweeXVoV7kc,2809
|
10
10
|
GameSentenceMiner/obs.py,sha256=MlxRToq5wALPI1XrD8rxEU-N8mWII91cNJWY7rUa5uI,7642
|
@@ -13,7 +13,7 @@ GameSentenceMiner/util.py,sha256=Awhy57vX4NgQzygqKaGQn2EJ75T0uiXlhmINFOWlQkU,682
|
|
13
13
|
GameSentenceMiner/utility_gui.py,sha256=H4aOddlsrVR768RwbMzYScCziuOz1JeySUigNrPlaac,7692
|
14
14
|
GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
|
15
15
|
GameSentenceMiner/communication/send.py,sha256=oOJdCS6-LNX90amkRn5FL2xqx6THGm56zHR2ntVIFTE,229
|
16
|
-
GameSentenceMiner/communication/websocket.py,sha256=
|
16
|
+
GameSentenceMiner/communication/websocket.py,sha256=pTcUe_ZZRp9REdSU4qalhPmbT_1DKa7w18j6RfFLELA,3074
|
17
17
|
GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
|
18
18
|
GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
GameSentenceMiner/downloader/download_tools.py,sha256=mI1u_FGBmBqDIpCH3jOv8DOoZ3obgP5pIf9o9SVfX2Q,8131
|
@@ -21,9 +21,9 @@ GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
21
21
|
GameSentenceMiner/vad/silero_trim.py,sha256=-thDIZLuTLra3YBj7WR16Z6JeDgSpge2YuahprBvD8I,1585
|
22
22
|
GameSentenceMiner/vad/vosk_helper.py,sha256=BI_mg_qyrjNbuEJjXSUDoV0FWEtQtEOAPmrrNixnZ_8,5974
|
23
23
|
GameSentenceMiner/vad/whisper_helper.py,sha256=OF4J8TPPoKPJR1uFwrWAZ2Q7v0HJkVvNGmF8l1tACX0,3447
|
24
|
-
gamesentenceminer-2.5.
|
25
|
-
gamesentenceminer-2.5.
|
26
|
-
gamesentenceminer-2.5.
|
27
|
-
gamesentenceminer-2.5.
|
28
|
-
gamesentenceminer-2.5.
|
29
|
-
gamesentenceminer-2.5.
|
24
|
+
gamesentenceminer-2.5.14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
25
|
+
gamesentenceminer-2.5.14.dist-info/METADATA,sha256=sm1RIt4O0bGoTOY3gMeVxcj7qbm_whFLk_6Jgf_blVk,5433
|
26
|
+
gamesentenceminer-2.5.14.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
27
|
+
gamesentenceminer-2.5.14.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
28
|
+
gamesentenceminer-2.5.14.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
29
|
+
gamesentenceminer-2.5.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|