GameSentenceMiner 2.12.12.post1__tar.gz → 2.13.1__tar.gz
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-2.13.1/GameSentenceMiner/config_gui.py +2116 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/gametext.py +2 -0
- gamesentenceminer-2.13.1/GameSentenceMiner/locales/en_us.json +592 -0
- gamesentenceminer-2.13.1/GameSentenceMiner/locales/ja_jp.json +591 -0
- gamesentenceminer-2.13.1/GameSentenceMiner/locales/zh_cn.json +592 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/configuration.py +41 -1
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/wip/get_overlay_coords.py +1 -1
- gamesentenceminer-2.13.1/GameSentenceMiner.egg-info/PKG-INFO +42 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner.egg-info/SOURCES.txt +3 -1
- gamesentenceminer-2.13.1/PKG-INFO +42 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/pyproject.toml +2 -2
- gamesentenceminer-2.12.12.post1/GameSentenceMiner/config_gui.py +0 -1881
- gamesentenceminer-2.12.12.post1/GameSentenceMiner.egg-info/PKG-INFO +0 -157
- gamesentenceminer-2.12.12.post1/PKG-INFO +0 -157
- gamesentenceminer-2.12.12.post1/README.md +0 -114
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ai/ai_prompting.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/anki.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/gsm.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/obs.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/owocr_helper.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/ocr.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/run.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/electron_config.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/ffmpeg.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/package.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/ss_selector.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/util/window_transparency.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/vad.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/templates/index.html +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/LICENSE +0 -0
- {gamesentenceminer-2.12.12.post1 → gamesentenceminer-2.13.1}/setup.cfg +0 -0
@@ -0,0 +1,2116 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import subprocess
|
4
|
+
import time
|
5
|
+
import tkinter as tk
|
6
|
+
from tkinter import filedialog, messagebox, simpledialog, scrolledtext, font
|
7
|
+
|
8
|
+
import pyperclip
|
9
|
+
import ttkbootstrap as ttk
|
10
|
+
|
11
|
+
from GameSentenceMiner import obs
|
12
|
+
from GameSentenceMiner.util import configuration
|
13
|
+
from GameSentenceMiner.util.communication.send import send_restart_signal
|
14
|
+
from GameSentenceMiner.util.configuration import *
|
15
|
+
from GameSentenceMiner.util.downloader.download_tools import download_ocenaudio_if_needed
|
16
|
+
from GameSentenceMiner.util.package import get_current_version, get_latest_version
|
17
|
+
|
18
|
+
settings_saved = False
|
19
|
+
on_save = []
|
20
|
+
exit_func = None
|
21
|
+
|
22
|
+
|
23
|
+
# It's assumed that a file named 'en_us.json' exists in the same directory
|
24
|
+
# or a path that Python can find.
|
25
|
+
def load_localization(locale=Locale.English):
|
26
|
+
"""Loads the localization file."""
|
27
|
+
try:
|
28
|
+
# Use a path relative to this script file
|
29
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
30
|
+
lang_file = os.path.join(script_dir, 'locales', f'{locale.value}.json')
|
31
|
+
with open(lang_file, 'r', encoding='utf-8') as f:
|
32
|
+
return json.load(f)['python']['config']
|
33
|
+
except (FileNotFoundError, json.JSONDecodeError) as e:
|
34
|
+
print(f"Warning: Could not load localization file '{locale.value}.json'. Error: {e}. Falling back to empty dict.")
|
35
|
+
return {}
|
36
|
+
|
37
|
+
|
38
|
+
def new_tab(func):
|
39
|
+
def wrapper(self, *args, **kwargs):
|
40
|
+
self.current_row = 0 # Resetting row for the new tab
|
41
|
+
# Perform any other pre-initialization tasks here if needed
|
42
|
+
return func(self, *args, **kwargs)
|
43
|
+
|
44
|
+
return wrapper
|
45
|
+
|
46
|
+
|
47
|
+
class HoverInfoWidget:
|
48
|
+
def __init__(self, parent, text, row, column, padx=5, pady=2):
|
49
|
+
self.info_icon = ttk.Label(parent, text="ⓘ", foreground="blue", cursor="hand2")
|
50
|
+
self.info_icon.grid(row=row, column=column, padx=padx, pady=pady)
|
51
|
+
self.info_icon.bind("<Enter>", lambda e: self.show_info_box(text))
|
52
|
+
self.info_icon.bind("<Leave>", lambda e: self.hide_info_box())
|
53
|
+
self.tooltip = None
|
54
|
+
|
55
|
+
def change_text(self, text):
|
56
|
+
"""
|
57
|
+
Change the text of the info icon.
|
58
|
+
"""
|
59
|
+
if self.tooltip:
|
60
|
+
self.tooltip.destroy()
|
61
|
+
self.tooltip = None
|
62
|
+
self.info_icon.config(text=text)
|
63
|
+
|
64
|
+
def show_info_box(self, text):
|
65
|
+
x, y, _, _ = self.info_icon.bbox("insert")
|
66
|
+
x += self.info_icon.winfo_rootx() + 25
|
67
|
+
y += self.info_icon.winfo_rooty() + 20
|
68
|
+
self.tooltip = tk.Toplevel(self.info_icon)
|
69
|
+
self.tooltip.wm_overrideredirect(True)
|
70
|
+
self.tooltip.wm_geometry(f"+{x}+{y}")
|
71
|
+
label = ttk.Label(self.tooltip, text=text, relief="solid", borderwidth=1,
|
72
|
+
font=("tahoma", "12", "normal"))
|
73
|
+
label.pack(ipadx=1)
|
74
|
+
|
75
|
+
def hide_info_box(self):
|
76
|
+
if self.tooltip:
|
77
|
+
self.tooltip.destroy()
|
78
|
+
self.tooltip = None
|
79
|
+
|
80
|
+
|
81
|
+
class HoverInfoLabelWidget:
|
82
|
+
def __init__(self, parent, text, tooltip, row, column, padx=5, pady=2, foreground="white", sticky='W',
|
83
|
+
bootstyle=None, font=("Arial", 10, "normal"), apply_to_parent=False, columnspan=1):
|
84
|
+
self.label_text_value = ttk.StringVar(value=text)
|
85
|
+
self.label = ttk.Label(parent, textvariable=self.label_text_value, foreground=foreground, cursor="hand2", bootstyle=bootstyle, font=font)
|
86
|
+
self.label.grid(row=row, column=column, padx=(0, padx), pady=0, sticky=sticky, columnspan=columnspan)
|
87
|
+
self.label.bind("<Enter>", lambda e: self.show_info_box(tooltip))
|
88
|
+
self.label.bind("<Leave>", lambda e: self.hide_info_box())
|
89
|
+
self.tooltip = None
|
90
|
+
|
91
|
+
def show_info_box(self, text):
|
92
|
+
x, y, _, _ = self.label.bbox("insert")
|
93
|
+
x += self.label.winfo_rootx() + 25
|
94
|
+
y += self.label.winfo_rooty() + 20
|
95
|
+
self.tooltip = tk.Toplevel(self.label)
|
96
|
+
self.tooltip.wm_overrideredirect(True)
|
97
|
+
self.tooltip.wm_geometry(f"+{x}+{y}")
|
98
|
+
label = ttk.Label(self.tooltip, text=text, relief="solid", borderwidth=1,
|
99
|
+
font=("tahoma", "12", "normal"))
|
100
|
+
label.pack(ipadx=1)
|
101
|
+
|
102
|
+
def hide_info_box(self):
|
103
|
+
if self.tooltip:
|
104
|
+
self.tooltip.destroy()
|
105
|
+
self.tooltip = None
|
106
|
+
|
107
|
+
|
108
|
+
class ResetToDefaultButton(ttk.Button):
|
109
|
+
def __init__(self, parent, command, text="Reset to Default", tooltip_text="Reset settings", bootstyle="danger", **kwargs):
|
110
|
+
super().__init__(parent, text=text, command=command, bootstyle=bootstyle, **kwargs)
|
111
|
+
self.tooltip_text = tooltip_text
|
112
|
+
self.tooltip = None
|
113
|
+
self.bind("<Enter>", self.show_tooltip)
|
114
|
+
self.bind("<Leave>", self.hide_tooltip)
|
115
|
+
|
116
|
+
def show_tooltip(self, event):
|
117
|
+
if not self.tooltip:
|
118
|
+
x = self.winfo_rootx() + 20
|
119
|
+
y = self.winfo_rooty() + 20
|
120
|
+
self.tooltip = tk.Toplevel(self)
|
121
|
+
self.tooltip.wm_overrideredirect(True)
|
122
|
+
self.tooltip.wm_geometry(f"+{x}+{y}")
|
123
|
+
label = ttk.Label(self.tooltip, text=self.tooltip_text, relief="solid",
|
124
|
+
borderwidth=1,
|
125
|
+
font=("tahoma", "12", "normal"))
|
126
|
+
label.pack(ipadx=1)
|
127
|
+
|
128
|
+
def hide_tooltip(self, event):
|
129
|
+
if self.tooltip:
|
130
|
+
self.tooltip.destroy()
|
131
|
+
self.tooltip = None
|
132
|
+
|
133
|
+
|
134
|
+
class ConfigApp:
|
135
|
+
def __init__(self, root):
|
136
|
+
self.window = root
|
137
|
+
self.on_exit = None
|
138
|
+
self.window.tk.call('tk', 'scaling', 1.5) # Set DPI scaling factor
|
139
|
+
self.window.protocol("WM_DELETE_WINDOW", self.hide)
|
140
|
+
self.obs_scene_listbox_changed = False
|
141
|
+
self.test_func = None
|
142
|
+
|
143
|
+
self.current_row = 0
|
144
|
+
|
145
|
+
self.master_config: Config = configuration.load_config()
|
146
|
+
self.i18n = load_localization(self.master_config.locale)
|
147
|
+
|
148
|
+
self.window.title(self.i18n.get('app', {}).get('title', 'GameSentenceMiner Configuration'))
|
149
|
+
|
150
|
+
self.settings = self.master_config.get_config()
|
151
|
+
self.default_master_settings = Config.new()
|
152
|
+
self.default_settings = self.default_master_settings.get_config()
|
153
|
+
|
154
|
+
self.notebook = ttk.Notebook(self.window)
|
155
|
+
self.notebook.pack(pady=10, expand=True, fill='both')
|
156
|
+
|
157
|
+
self.required_settings_frame = None
|
158
|
+
self.starter_tab = None
|
159
|
+
self.general_tab = None
|
160
|
+
self.paths_tab = None
|
161
|
+
self.anki_tab = None
|
162
|
+
self.vad_tab = None
|
163
|
+
self.features_tab = None
|
164
|
+
self.screenshot_tab = None
|
165
|
+
self.audio_tab = None
|
166
|
+
self.obs_tab = None
|
167
|
+
self.profiles_tab = None
|
168
|
+
self.ai_tab = None
|
169
|
+
self.advanced_tab = None
|
170
|
+
self.wip_tab = None
|
171
|
+
self.monitors = []
|
172
|
+
|
173
|
+
try:
|
174
|
+
import mss as mss
|
175
|
+
self.monitors = [f"Monitor {i}: width: {monitor['width']}, height: {monitor['height']}" for i, monitor in enumerate(mss.mss().monitors[1:], start=1)]
|
176
|
+
if len(self.monitors) == 0:
|
177
|
+
self.monitors = [1]
|
178
|
+
except ImportError:
|
179
|
+
self.monitors = []
|
180
|
+
|
181
|
+
self.create_vars()
|
182
|
+
self.create_tabs()
|
183
|
+
self.notebook.bind("<<NotebookTabChanged>>", self.on_profiles_tab_selected)
|
184
|
+
|
185
|
+
button_frame = ttk.Frame(self.window)
|
186
|
+
button_frame.pack(side="bottom", pady=20, anchor="center")
|
187
|
+
|
188
|
+
buttons_i18n = self.i18n.get('buttons', {})
|
189
|
+
self.save_button = ttk.Button(button_frame, text=buttons_i18n.get('save', 'Save Settings'), command=self.save_settings, bootstyle="success")
|
190
|
+
self.save_button.grid(row=0, column=0, padx=10)
|
191
|
+
|
192
|
+
if len(self.master_config.configs) > 1:
|
193
|
+
self.sync_changes_var = tk.BooleanVar(value=False)
|
194
|
+
sync_btn_i18n = buttons_i18n.get('sync_changes', {})
|
195
|
+
self.sync_changes_checkbutton = ttk.Checkbutton(
|
196
|
+
button_frame,
|
197
|
+
text=sync_btn_i18n.get('label', 'Sync Changes to Profiles'),
|
198
|
+
variable=self.sync_changes_var,
|
199
|
+
bootstyle="info"
|
200
|
+
)
|
201
|
+
self.sync_changes_checkbutton.grid(row=0, column=1, padx=10)
|
202
|
+
self.sync_changes_hover_info = HoverInfoWidget(
|
203
|
+
button_frame,
|
204
|
+
sync_btn_i18n.get('tooltip', 'Syncs CHANGED SETTINGS to all profiles.'),
|
205
|
+
row=0,
|
206
|
+
column=2
|
207
|
+
)
|
208
|
+
|
209
|
+
self.window.update_idletasks()
|
210
|
+
self.window.geometry("")
|
211
|
+
self.window.withdraw()
|
212
|
+
|
213
|
+
def change_locale(self):
|
214
|
+
"""Change the locale of the application."""
|
215
|
+
if self.locale_value.get() == self.master_config.locale.name:
|
216
|
+
return
|
217
|
+
self.i18n = load_localization(Locale[self.locale_value.get()])
|
218
|
+
self.save_settings()
|
219
|
+
self.reload_settings(force_refresh=True)
|
220
|
+
|
221
|
+
self.window.title(self.i18n.get('app', {}).get('title', 'GameSentenceMiner Configuration'))
|
222
|
+
self.save_button.config(text=self.i18n.get('buttons', {}).get('save', 'Save Settings'))
|
223
|
+
if hasattr(self, 'sync_changes_checkbutton'):
|
224
|
+
self.sync_changes_checkbutton.config(text=self.i18n.get('buttons', {}).get('sync_changes', {}).get('label', 'Sync Changes to Profiles'))
|
225
|
+
|
226
|
+
logger.info(f"Locale changed to {self.locale_value.get()}.")
|
227
|
+
|
228
|
+
def set_test_func(self, func):
|
229
|
+
self.test_func = func
|
230
|
+
|
231
|
+
def create_vars(self):
|
232
|
+
"""
|
233
|
+
Initializes all the tkinter variables used in the configuration GUI.
|
234
|
+
"""
|
235
|
+
# General Settings
|
236
|
+
self.websocket_enabled_value = tk.BooleanVar(value=self.settings.general.use_websocket)
|
237
|
+
self.clipboard_enabled_value = tk.BooleanVar(value=self.settings.general.use_clipboard)
|
238
|
+
self.use_both_clipboard_and_websocket_value = tk.BooleanVar(value=self.settings.general.use_both_clipboard_and_websocket)
|
239
|
+
self.merge_matching_sequential_text_value = tk.BooleanVar(value=self.settings.general.merge_matching_sequential_text)
|
240
|
+
self.websocket_uri_value = tk.StringVar(value=self.settings.general.websocket_uri)
|
241
|
+
self.texthook_replacement_regex_value = tk.StringVar(value=self.settings.general.texthook_replacement_regex)
|
242
|
+
self.open_config_on_startup_value = tk.BooleanVar(value=self.settings.general.open_config_on_startup)
|
243
|
+
self.open_multimine_on_startup_value = tk.BooleanVar(value=self.settings.general.open_multimine_on_startup)
|
244
|
+
self.texthooker_port_value = tk.StringVar(value=str(self.settings.general.texthooker_port))
|
245
|
+
self.native_language_value = tk.StringVar(value=CommonLanguages.from_code(self.settings.general.native_language).name.replace('_', ' ').title())
|
246
|
+
|
247
|
+
# OBS Settings
|
248
|
+
self.obs_enabled_value = tk.BooleanVar(value=self.settings.obs.enabled)
|
249
|
+
self.obs_websocket_port_value = tk.StringVar(value=str(self.settings.obs.port))
|
250
|
+
self.obs_host_value = tk.StringVar(value=self.settings.obs.host)
|
251
|
+
self.obs_port_value = tk.StringVar(value=str(self.settings.obs.port))
|
252
|
+
self.obs_password_value = tk.StringVar(value=self.settings.obs.password)
|
253
|
+
self.obs_open_obs_value = tk.BooleanVar(value=self.settings.obs.open_obs)
|
254
|
+
self.obs_close_obs_value = tk.BooleanVar(value=self.settings.obs.close_obs)
|
255
|
+
self.obs_get_game_from_scene_name_value = tk.BooleanVar(value=self.settings.obs.get_game_from_scene)
|
256
|
+
self.obs_minimum_replay_size_value = tk.StringVar(value=str(self.settings.obs.minimum_replay_size))
|
257
|
+
|
258
|
+
# Paths Settings
|
259
|
+
self.folder_to_watch_value = tk.StringVar(value=self.settings.paths.folder_to_watch)
|
260
|
+
self.audio_destination_value = tk.StringVar(value=self.settings.paths.audio_destination)
|
261
|
+
self.screenshot_destination_value = tk.StringVar(value=self.settings.paths.screenshot_destination)
|
262
|
+
self.remove_video_value = tk.BooleanVar(value=self.settings.paths.remove_video)
|
263
|
+
self.remove_audio_value = tk.BooleanVar(value=self.settings.paths.remove_audio)
|
264
|
+
self.remove_screenshot_value = tk.BooleanVar(value=self.settings.paths.remove_screenshot)
|
265
|
+
|
266
|
+
# Anki Settings
|
267
|
+
self.update_anki_value = tk.BooleanVar(value=self.settings.anki.update_anki)
|
268
|
+
self.anki_url_value = tk.StringVar(value=self.settings.anki.url)
|
269
|
+
self.sentence_field_value = tk.StringVar(value=self.settings.anki.sentence_field)
|
270
|
+
self.sentence_audio_field_value = tk.StringVar(value=self.settings.anki.sentence_audio_field)
|
271
|
+
self.picture_field_value = tk.StringVar(value=self.settings.anki.picture_field)
|
272
|
+
self.word_field_value = tk.StringVar(value=self.settings.anki.word_field)
|
273
|
+
self.previous_sentence_field_value = tk.StringVar(value=self.settings.anki.previous_sentence_field)
|
274
|
+
self.previous_image_field_value = tk.StringVar(value=self.settings.anki.previous_image_field)
|
275
|
+
self.custom_tags_value = tk.StringVar(value=', '.join(self.settings.anki.custom_tags))
|
276
|
+
self.tags_to_check_value = tk.StringVar(value=', '.join(self.settings.anki.tags_to_check))
|
277
|
+
self.add_game_tag_value = tk.BooleanVar(value=self.settings.anki.add_game_tag)
|
278
|
+
self.polling_rate_value = tk.StringVar(value=str(self.settings.anki.polling_rate))
|
279
|
+
self.overwrite_audio_value = tk.BooleanVar(value=self.settings.anki.overwrite_audio)
|
280
|
+
self.overwrite_picture_value = tk.BooleanVar(value=self.settings.anki.overwrite_picture)
|
281
|
+
self.multi_overwrites_sentence_value = tk.BooleanVar(value=self.settings.anki.multi_overwrites_sentence)
|
282
|
+
self.parent_tag_value = tk.StringVar(value=self.settings.anki.parent_tag)
|
283
|
+
|
284
|
+
# Features Settings
|
285
|
+
self.full_auto_value = tk.BooleanVar(value=self.settings.features.full_auto)
|
286
|
+
self.notify_on_update_value = tk.BooleanVar(value=self.settings.features.notify_on_update)
|
287
|
+
self.open_anki_edit_value = tk.BooleanVar(value=self.settings.features.open_anki_edit)
|
288
|
+
self.open_anki_browser_value = tk.BooleanVar(value=self.settings.features.open_anki_in_browser)
|
289
|
+
self.backfill_audio_value = tk.BooleanVar(value=self.settings.features.backfill_audio)
|
290
|
+
self.browser_query_value = tk.StringVar(value=self.settings.features.browser_query)
|
291
|
+
|
292
|
+
# Screenshot Settings
|
293
|
+
self.screenshot_enabled_value = tk.BooleanVar(value=self.settings.screenshot.enabled)
|
294
|
+
self.screenshot_width_value = tk.StringVar(value=str(self.settings.screenshot.width))
|
295
|
+
self.screenshot_height_value = tk.StringVar(value=str(self.settings.screenshot.height))
|
296
|
+
self.screenshot_quality_value = tk.StringVar(value=str(self.settings.screenshot.quality))
|
297
|
+
self.screenshot_extension_value = tk.StringVar(value=self.settings.screenshot.extension)
|
298
|
+
self.screenshot_custom_ffmpeg_settings_value = tk.StringVar(value=self.settings.screenshot.custom_ffmpeg_settings)
|
299
|
+
self.screenshot_hotkey_update_anki_value = tk.BooleanVar(value=self.settings.screenshot.screenshot_hotkey_updates_anki)
|
300
|
+
self.seconds_after_line_value = tk.StringVar(value=str(self.settings.screenshot.seconds_after_line))
|
301
|
+
self.screenshot_timing_value = tk.StringVar(value=self.settings.screenshot.screenshot_timing_setting)
|
302
|
+
self.use_screenshot_selector_value = tk.BooleanVar(value=self.settings.screenshot.use_screenshot_selector)
|
303
|
+
|
304
|
+
# Audio Settings
|
305
|
+
self.audio_enabled_value = tk.BooleanVar(value=self.settings.audio.enabled)
|
306
|
+
self.audio_extension_value = tk.StringVar(value=self.settings.audio.extension)
|
307
|
+
self.beginning_offset_value = tk.StringVar(value=str(self.settings.audio.beginning_offset))
|
308
|
+
self.end_offset_value = tk.StringVar(value=str(self.settings.audio.end_offset))
|
309
|
+
self.audio_ffmpeg_reencode_options_value = tk.StringVar(value=self.settings.audio.ffmpeg_reencode_options)
|
310
|
+
self.external_tool_value = tk.StringVar(value=self.settings.audio.external_tool)
|
311
|
+
self.anki_media_collection_value = tk.StringVar(value=self.settings.audio.anki_media_collection)
|
312
|
+
self.external_tool_enabled_value = tk.BooleanVar(value=self.settings.audio.external_tool_enabled)
|
313
|
+
self.pre_vad_audio_offset_value = tk.StringVar(value=str(self.settings.audio.pre_vad_end_offset))
|
314
|
+
|
315
|
+
# Hotkeys Settings
|
316
|
+
self.reset_line_hotkey_value = tk.StringVar(value=self.settings.hotkeys.reset_line)
|
317
|
+
self.take_screenshot_hotkey_value = tk.StringVar(value=self.settings.hotkeys.take_screenshot)
|
318
|
+
self.play_latest_audio_hotkey_value = tk.StringVar(value=self.settings.hotkeys.play_latest_audio)
|
319
|
+
|
320
|
+
# VAD Settings
|
321
|
+
self.whisper_model_value = tk.StringVar(value=self.settings.vad.whisper_model)
|
322
|
+
self.do_vad_postprocessing_value = tk.BooleanVar(value=self.settings.vad.do_vad_postprocessing)
|
323
|
+
self.selected_vad_model_value = tk.StringVar(value=self.settings.vad.selected_vad_model)
|
324
|
+
self.backup_vad_model_value = tk.StringVar(value=self.settings.vad.backup_vad_model)
|
325
|
+
self.vad_trim_beginning_value = tk.BooleanVar(value=self.settings.vad.trim_beginning)
|
326
|
+
self.vad_beginning_offset_value = tk.StringVar(value=str(self.settings.vad.beginning_offset))
|
327
|
+
self.add_audio_on_no_results_value = tk.BooleanVar(value=self.settings.vad.add_audio_on_no_results)
|
328
|
+
self.language_value = tk.StringVar(value=self.settings.vad.language)
|
329
|
+
self.cut_and_splice_segments_value = tk.BooleanVar(value=self.settings.vad.cut_and_splice_segments)
|
330
|
+
self.splice_padding_value = tk.StringVar(value=str(self.settings.vad.splice_padding) if self.settings.vad.splice_padding else "")
|
331
|
+
|
332
|
+
# Advanced Settings
|
333
|
+
self.audio_player_path_value = tk.StringVar(value=self.settings.advanced.audio_player_path)
|
334
|
+
self.video_player_path_value = tk.StringVar(value=self.settings.advanced.video_player_path)
|
335
|
+
self.multi_line_line_break_value = tk.StringVar(value=self.settings.advanced.multi_line_line_break)
|
336
|
+
self.multi_line_sentence_storage_field_value = tk.StringVar(value=self.settings.advanced.multi_line_sentence_storage_field)
|
337
|
+
self.ocr_websocket_port_value = tk.StringVar(value=str(self.settings.advanced.ocr_websocket_port))
|
338
|
+
self.texthooker_communication_websocket_port_value = tk.StringVar(value=str(self.settings.advanced.texthooker_communication_websocket_port))
|
339
|
+
self.plaintext_websocket_export_port_value = tk.StringVar(value=str(self.settings.advanced.plaintext_websocket_port))
|
340
|
+
|
341
|
+
# AI Settings
|
342
|
+
self.ai_enabled_value = tk.BooleanVar(value=self.settings.ai.enabled)
|
343
|
+
self.ai_provider_value = tk.StringVar(value=self.settings.ai.provider)
|
344
|
+
self.gemini_model_value = tk.StringVar(value=self.settings.ai.gemini_model)
|
345
|
+
self.groq_model_value = tk.StringVar(value=self.settings.ai.groq_model)
|
346
|
+
self.gemini_api_key_value = tk.StringVar(value=self.settings.ai.gemini_api_key)
|
347
|
+
self.groq_api_key_value = tk.StringVar(value=self.settings.ai.groq_api_key)
|
348
|
+
self.local_ai_model_value = tk.StringVar(value=self.settings.ai.local_model)
|
349
|
+
self.ai_anki_field_value = tk.StringVar(value=self.settings.ai.anki_field)
|
350
|
+
self.use_canned_translation_prompt_value = tk.BooleanVar(value=self.settings.ai.use_canned_translation_prompt)
|
351
|
+
self.use_canned_context_prompt_value = tk.BooleanVar(value=self.settings.ai.use_canned_context_prompt)
|
352
|
+
self.ai_dialogue_context_length_value = tk.StringVar(value=str(self.settings.ai.dialogue_context_length))
|
353
|
+
|
354
|
+
# WIP Settings
|
355
|
+
self.overlay_websocket_port_value = tk.StringVar(value=str(self.settings.wip.overlay_websocket_port))
|
356
|
+
self.overlay_websocket_send_value = tk.BooleanVar(value=self.settings.wip.overlay_websocket_send)
|
357
|
+
|
358
|
+
# Master Config Settings
|
359
|
+
self.switch_to_default_if_not_found_value = tk.BooleanVar(value=self.master_config.switch_to_default_if_not_found)
|
360
|
+
self.locale_value = tk.StringVar(value=self.master_config.locale.name)
|
361
|
+
|
362
|
+
|
363
|
+
def create_tabs(self):
|
364
|
+
self.create_required_settings_tab()
|
365
|
+
self.create_general_tab()
|
366
|
+
self.create_paths_tab()
|
367
|
+
self.create_anki_tab()
|
368
|
+
self.create_vad_tab()
|
369
|
+
self.create_features_tab()
|
370
|
+
self.create_screenshot_tab()
|
371
|
+
self.create_audio_tab()
|
372
|
+
self.create_obs_tab()
|
373
|
+
self.create_profiles_tab()
|
374
|
+
self.create_ai_tab()
|
375
|
+
self.create_advanced_tab()
|
376
|
+
self.create_wip_tab()
|
377
|
+
|
378
|
+
def add_reset_button(self, frame, category, row, column=0, recreate_tab=None):
|
379
|
+
"""
|
380
|
+
Adds a reset button to the given frame that resets the settings in the frame to default values.
|
381
|
+
"""
|
382
|
+
reset_btn_i18n = self.i18n.get('buttons', {}).get('reset_to_default', {})
|
383
|
+
reset_button = ResetToDefaultButton(frame, command=lambda: self.reset_to_default(category, recreate_tab),
|
384
|
+
text=reset_btn_i18n.get('text', 'Reset to Default'),
|
385
|
+
tooltip_text=reset_btn_i18n.get('tooltip', 'Reset current tab to default.'))
|
386
|
+
reset_button.grid(row=row, column=column, sticky='W', padx=5, pady=5)
|
387
|
+
return reset_button
|
388
|
+
|
389
|
+
def reset_to_default(self, category, recreate_tab):
|
390
|
+
"""
|
391
|
+
Resets the settings in the current tab to default values.
|
392
|
+
"""
|
393
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('reset_to_default', {})
|
394
|
+
if not messagebox.askyesno(dialog_i18n.get('title', 'Reset to Default'),
|
395
|
+
dialog_i18n.get('message', 'Are you sure you want to reset all settings in this tab to default?')):
|
396
|
+
return
|
397
|
+
|
398
|
+
default_category_config = getattr(self.default_settings, category)
|
399
|
+
|
400
|
+
setattr(self.settings, category, default_category_config)
|
401
|
+
recreate_tab()
|
402
|
+
self.save_settings(profile_change=False)
|
403
|
+
self.reload_settings()
|
404
|
+
|
405
|
+
def show_scene_selection(self, matched_configs):
|
406
|
+
selected_scene = None
|
407
|
+
if matched_configs:
|
408
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('select_profile', {})
|
409
|
+
buttons_i18n = self.i18n.get('buttons', {})
|
410
|
+
|
411
|
+
selection_window = tk.Toplevel(self.window)
|
412
|
+
selection_window.title(dialog_i18n.get('title', 'Select Profile'))
|
413
|
+
selection_window.transient(self.window)
|
414
|
+
selection_window.grab_set()
|
415
|
+
|
416
|
+
ttk.Label(selection_window,
|
417
|
+
text=dialog_i18n.get('message', 'Multiple profiles match... Please select:')).pack(pady=10)
|
418
|
+
profile_var = tk.StringVar(value=matched_configs[0])
|
419
|
+
profile_dropdown = ttk.Combobox(selection_window, textvariable=profile_var, values=matched_configs,
|
420
|
+
state="readonly")
|
421
|
+
profile_dropdown.pack(pady=5)
|
422
|
+
ttk.Button(selection_window, text=buttons_i18n.get('ok', 'OK'),
|
423
|
+
command=lambda: [selection_window.destroy(), setattr(self, 'selected_scene', profile_var.get())],
|
424
|
+
bootstyle="primary").pack(pady=10)
|
425
|
+
|
426
|
+
self.window.wait_window(selection_window)
|
427
|
+
selected_scene = self.selected_scene
|
428
|
+
return selected_scene
|
429
|
+
|
430
|
+
def add_save_hook(self, func):
|
431
|
+
on_save.append(func)
|
432
|
+
|
433
|
+
def show(self):
|
434
|
+
logger.info("Showing Configuration Window")
|
435
|
+
obs.update_current_game()
|
436
|
+
self.reload_settings()
|
437
|
+
if self.window is not None:
|
438
|
+
self.window.deiconify()
|
439
|
+
self.window.lift()
|
440
|
+
self.window.update_idletasks()
|
441
|
+
return
|
442
|
+
|
443
|
+
def hide(self):
|
444
|
+
if self.window is not None:
|
445
|
+
self.window.withdraw()
|
446
|
+
|
447
|
+
def save_settings(self, profile_change=False, sync_changes=False):
|
448
|
+
global settings_saved
|
449
|
+
|
450
|
+
sync_changes = self.sync_changes_checkbutton.instate(['selected']) if hasattr(self, 'sync_changes_checkbutton') else sync_changes
|
451
|
+
# reset checkbox
|
452
|
+
if hasattr(self, 'sync_changes_checkbutton'):
|
453
|
+
self.sync_changes_checkbutton.state(['!selected'])
|
454
|
+
|
455
|
+
# Create a new Config instance
|
456
|
+
config = ProfileConfig(
|
457
|
+
scenes=self.settings.scenes,
|
458
|
+
general=General(
|
459
|
+
use_websocket=self.websocket_enabled_value.get(),
|
460
|
+
use_clipboard=self.clipboard_enabled_value.get(),
|
461
|
+
websocket_uri=self.websocket_uri_value.get(),
|
462
|
+
merge_matching_sequential_text= self.merge_matching_sequential_text_value.get(),
|
463
|
+
open_config_on_startup=self.open_config_on_startup_value.get(),
|
464
|
+
open_multimine_on_startup=self.open_multimine_on_startup_value.get(),
|
465
|
+
texthook_replacement_regex=self.texthook_replacement_regex_value.get(),
|
466
|
+
use_both_clipboard_and_websocket=self.use_both_clipboard_and_websocket_value.get(),
|
467
|
+
texthooker_port=int(self.texthooker_port_value.get()),
|
468
|
+
native_language=CommonLanguages.from_name(self.native_language_value.get()) if self.native_language_value.get() else CommonLanguages.ENGLISH.value,
|
469
|
+
),
|
470
|
+
paths=Paths(
|
471
|
+
folder_to_watch=self.folder_to_watch_value.get(),
|
472
|
+
audio_destination=self.audio_destination_value.get(),
|
473
|
+
screenshot_destination=self.screenshot_destination_value.get(),
|
474
|
+
remove_video=self.remove_video_value.get(),
|
475
|
+
remove_audio=self.remove_audio_value.get(),
|
476
|
+
remove_screenshot=self.remove_screenshot_value.get()
|
477
|
+
),
|
478
|
+
anki=Anki(
|
479
|
+
update_anki=self.update_anki_value.get(),
|
480
|
+
url=self.anki_url_value.get(),
|
481
|
+
sentence_field=self.sentence_field_value.get(),
|
482
|
+
sentence_audio_field=self.sentence_audio_field_value.get(),
|
483
|
+
picture_field=self.picture_field_value.get(),
|
484
|
+
word_field=self.word_field_value.get(),
|
485
|
+
previous_sentence_field=self.previous_sentence_field_value.get(),
|
486
|
+
previous_image_field=self.previous_image_field_value.get(),
|
487
|
+
custom_tags=[tag.strip() for tag in self.custom_tags_value.get().split(',') if tag.strip()],
|
488
|
+
tags_to_check=[tag.strip().lower() for tag in self.tags_to_check_value.get().split(',') if tag.strip()],
|
489
|
+
add_game_tag=self.add_game_tag_value.get(),
|
490
|
+
polling_rate=int(self.polling_rate_value.get()),
|
491
|
+
overwrite_audio=self.overwrite_audio_value.get(),
|
492
|
+
overwrite_picture=self.overwrite_picture_value.get(),
|
493
|
+
multi_overwrites_sentence=self.multi_overwrites_sentence_value.get(),
|
494
|
+
parent_tag=self.parent_tag_value.get(),
|
495
|
+
),
|
496
|
+
features=Features(
|
497
|
+
full_auto=self.full_auto_value.get(),
|
498
|
+
notify_on_update=self.notify_on_update_value.get(),
|
499
|
+
open_anki_edit=self.open_anki_edit_value.get(),
|
500
|
+
open_anki_in_browser=self.open_anki_browser_value.get(),
|
501
|
+
backfill_audio=self.backfill_audio_value.get(),
|
502
|
+
browser_query=self.browser_query_value.get(),
|
503
|
+
),
|
504
|
+
screenshot=Screenshot(
|
505
|
+
enabled=self.screenshot_enabled_value.get(),
|
506
|
+
width=self.screenshot_width_value.get(),
|
507
|
+
height=self.screenshot_height_value.get(),
|
508
|
+
quality=self.screenshot_quality_value.get(),
|
509
|
+
extension=self.screenshot_extension_value.get(),
|
510
|
+
custom_ffmpeg_settings=self.screenshot_custom_ffmpeg_settings_value.get(),
|
511
|
+
screenshot_hotkey_updates_anki=self.screenshot_hotkey_update_anki_value.get(),
|
512
|
+
seconds_after_line=float(self.seconds_after_line_value.get()) if self.seconds_after_line_value.get() else 0.0,
|
513
|
+
screenshot_timing_setting=self.screenshot_timing_value.get(),
|
514
|
+
use_screenshot_selector=self.use_screenshot_selector_value.get(),
|
515
|
+
),
|
516
|
+
audio=Audio(
|
517
|
+
enabled=self.audio_enabled_value.get(),
|
518
|
+
extension=self.audio_extension_value.get(),
|
519
|
+
beginning_offset=float(self.beginning_offset_value.get()),
|
520
|
+
end_offset=float(self.end_offset_value.get()),
|
521
|
+
ffmpeg_reencode_options=self.audio_ffmpeg_reencode_options_value.get(),
|
522
|
+
external_tool=self.external_tool_value.get(),
|
523
|
+
anki_media_collection=self.anki_media_collection_value.get(),
|
524
|
+
external_tool_enabled=self.external_tool_enabled_value.get(),
|
525
|
+
pre_vad_end_offset=float(self.pre_vad_audio_offset_value.get()),
|
526
|
+
),
|
527
|
+
obs=OBS(
|
528
|
+
enabled=self.obs_enabled_value.get(),
|
529
|
+
open_obs=self.obs_open_obs_value.get(),
|
530
|
+
close_obs=self.obs_close_obs_value.get(),
|
531
|
+
host=self.obs_host_value.get(),
|
532
|
+
port=int(self.obs_port_value.get()),
|
533
|
+
password=self.obs_password_value.get(),
|
534
|
+
get_game_from_scene=self.obs_get_game_from_scene_name_value.get(),
|
535
|
+
minimum_replay_size=int(self.obs_minimum_replay_size_value.get())
|
536
|
+
),
|
537
|
+
hotkeys=Hotkeys(
|
538
|
+
reset_line=self.reset_line_hotkey_value.get(),
|
539
|
+
take_screenshot=self.take_screenshot_hotkey_value.get(),
|
540
|
+
play_latest_audio=self.play_latest_audio_hotkey_value.get()
|
541
|
+
),
|
542
|
+
vad=VAD(
|
543
|
+
whisper_model=self.whisper_model_value.get(),
|
544
|
+
do_vad_postprocessing=self.do_vad_postprocessing_value.get(),
|
545
|
+
selected_vad_model=self.selected_vad_model_value.get(),
|
546
|
+
backup_vad_model=self.backup_vad_model_value.get(),
|
547
|
+
trim_beginning=self.vad_trim_beginning_value.get(),
|
548
|
+
beginning_offset=float(self.vad_beginning_offset_value.get()),
|
549
|
+
add_audio_on_no_results=self.add_audio_on_no_results_value.get(),
|
550
|
+
language=self.language_value.get(),
|
551
|
+
cut_and_splice_segments=self.cut_and_splice_segments_value.get(),
|
552
|
+
splice_padding=float(self.splice_padding_value.get()) if self.splice_padding_value.get() else 0.0,
|
553
|
+
),
|
554
|
+
advanced=Advanced(
|
555
|
+
audio_player_path=self.audio_player_path_value.get(),
|
556
|
+
video_player_path=self.video_player_path_value.get(),
|
557
|
+
multi_line_line_break=self.multi_line_line_break_value.get(),
|
558
|
+
multi_line_sentence_storage_field=self.multi_line_sentence_storage_field_value.get(),
|
559
|
+
ocr_websocket_port=int(self.ocr_websocket_port_value.get()),
|
560
|
+
texthooker_communication_websocket_port=int(self.texthooker_communication_websocket_port_value.get()),
|
561
|
+
plaintext_websocket_port=int(self.plaintext_websocket_export_port_value.get()),
|
562
|
+
),
|
563
|
+
ai=Ai(
|
564
|
+
enabled=self.ai_enabled_value.get(),
|
565
|
+
provider=self.ai_provider_value.get(),
|
566
|
+
gemini_model=self.gemini_model_value.get(),
|
567
|
+
groq_model=self.groq_model_value.get(),
|
568
|
+
gemini_api_key=self.gemini_api_key_value.get(),
|
569
|
+
api_key=self.gemini_api_key_value.get(),
|
570
|
+
groq_api_key=self.groq_api_key_value.get(),
|
571
|
+
local_model=self.local_ai_model_value.get(),
|
572
|
+
anki_field=self.ai_anki_field_value.get(),
|
573
|
+
use_canned_translation_prompt=self.use_canned_translation_prompt_value.get(),
|
574
|
+
use_canned_context_prompt=self.use_canned_context_prompt_value.get(),
|
575
|
+
custom_prompt=self.custom_prompt.get("1.0", tk.END).strip(),
|
576
|
+
dialogue_context_length=int(self.ai_dialogue_context_length_value.get()),
|
577
|
+
),
|
578
|
+
wip=WIP(
|
579
|
+
overlay_websocket_port=int(self.overlay_websocket_port_value.get()),
|
580
|
+
overlay_websocket_send=self.overlay_websocket_send_value.get(),
|
581
|
+
monitor_to_capture=self.monitor_to_capture.current() if self.monitors else 0
|
582
|
+
)
|
583
|
+
)
|
584
|
+
|
585
|
+
# Find the display name for "Custom" to check against
|
586
|
+
audio_i18n = self.i18n.get('tabs', {}).get('audio', {})
|
587
|
+
ffmpeg_preset_i18n = audio_i18n.get('ffmpeg_preset', {}).get('options', {})
|
588
|
+
custom_display_name = ffmpeg_preset_i18n.get('custom', 'Custom')
|
589
|
+
|
590
|
+
if self.ffmpeg_audio_preset_options.get() == custom_display_name:
|
591
|
+
config.audio.custom_encode_settings = self.audio_ffmpeg_reencode_options_value.get()
|
592
|
+
|
593
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('config_error', {})
|
594
|
+
error_title = dialog_i18n.get('title', 'Configuration Error')
|
595
|
+
|
596
|
+
if config.features.backfill_audio and config.features.full_auto:
|
597
|
+
messagebox.showerror(error_title,
|
598
|
+
dialog_i18n.get('full_auto_and_backfill', 'Cannot have Full Auto and Backfill...'))
|
599
|
+
return
|
600
|
+
|
601
|
+
if not config.general.use_websocket and not config.general.use_clipboard:
|
602
|
+
messagebox.showerror(error_title, dialog_i18n.get('no_input_method', 'Cannot have both...'))
|
603
|
+
return
|
604
|
+
|
605
|
+
current_profile = self.profile_combobox.get()
|
606
|
+
prev_config = self.master_config.get_config()
|
607
|
+
self.master_config.switch_to_default_if_not_found = self.switch_to_default_if_not_found_value.get()
|
608
|
+
if profile_change:
|
609
|
+
self.master_config.current_profile = current_profile
|
610
|
+
else:
|
611
|
+
self.master_config.current_profile = current_profile
|
612
|
+
self.master_config.set_config_for_profile(current_profile, config)
|
613
|
+
|
614
|
+
self.master_config.locale = Locale[self.locale_value.get()].value
|
615
|
+
|
616
|
+
|
617
|
+
config_backup_folder = os.path.join(get_app_directory(), "backup", "config")
|
618
|
+
os.makedirs(config_backup_folder, exist_ok=True)
|
619
|
+
timestamp = time.strftime("%Y-%m-%d_%H-%M-%S")
|
620
|
+
with open(os.path.join(config_backup_folder, f"config_backup_{timestamp}.json"), 'w') as backup_file:
|
621
|
+
backup_file.write(self.master_config.to_json(indent=4))
|
622
|
+
|
623
|
+
self.master_config = self.master_config.sync_shared_fields()
|
624
|
+
|
625
|
+
if sync_changes:
|
626
|
+
self.master_config.sync_changed_fields(prev_config)
|
627
|
+
|
628
|
+
with open(get_config_path(), 'w') as file:
|
629
|
+
file.write(self.master_config.to_json(indent=4))
|
630
|
+
|
631
|
+
logger.info("Settings saved successfully!")
|
632
|
+
|
633
|
+
if self.master_config.get_config().restart_required(prev_config):
|
634
|
+
logger.info("Restart Required for some settings to take affect!")
|
635
|
+
asyncio.run(send_restart_signal())
|
636
|
+
|
637
|
+
settings_saved = True
|
638
|
+
configuration.reload_config()
|
639
|
+
self.settings = get_config()
|
640
|
+
for func in on_save:
|
641
|
+
func()
|
642
|
+
|
643
|
+
def reload_settings(self, force_refresh=False):
|
644
|
+
new_config = configuration.load_config()
|
645
|
+
current_config = new_config.get_config()
|
646
|
+
|
647
|
+
title_template = self.i18n.get('app', {}).get('title_with_profile', 'GameSentenceMiner Configuration - {profile_name}')
|
648
|
+
self.window.title(title_template.format(profile_name=current_config.name))
|
649
|
+
|
650
|
+
if current_config.name != self.settings.name or self.settings.config_changed(current_config) or force_refresh:
|
651
|
+
logger.info("Config changed, reloading settings.")
|
652
|
+
self.master_config = new_config
|
653
|
+
self.settings = current_config
|
654
|
+
for frame in self.notebook.winfo_children():
|
655
|
+
frame.destroy()
|
656
|
+
|
657
|
+
self.required_settings_frame = None
|
658
|
+
self.general_tab = None
|
659
|
+
self.paths_tab = None
|
660
|
+
self.anki_tab = None
|
661
|
+
self.vad_tab = None
|
662
|
+
self.features_tab = None
|
663
|
+
self.screenshot_tab = None
|
664
|
+
self.audio_tab = None
|
665
|
+
self.obs_tab = None
|
666
|
+
self.profiles_tab = None
|
667
|
+
self.ai_tab = None
|
668
|
+
self.advanced_tab = None
|
669
|
+
self.wip_tab = None
|
670
|
+
|
671
|
+
self.create_vars()
|
672
|
+
self.create_tabs()
|
673
|
+
|
674
|
+
def increment_row(self):
|
675
|
+
self.current_row += 1
|
676
|
+
return self.current_row
|
677
|
+
|
678
|
+
@new_tab
|
679
|
+
def create_general_tab(self):
|
680
|
+
if self.general_tab is None:
|
681
|
+
general_i18n = self.i18n.get('tabs', {}).get('general', {})
|
682
|
+
self.general_tab = ttk.Frame(self.notebook, padding=15)
|
683
|
+
self.notebook.add(self.general_tab, text=general_i18n.get('title', 'General'))
|
684
|
+
else:
|
685
|
+
for widget in self.general_tab.winfo_children():
|
686
|
+
widget.destroy()
|
687
|
+
|
688
|
+
general_i18n = self.i18n.get('tabs', {}).get('general', {})
|
689
|
+
|
690
|
+
ws_i18n = general_i18n.get('websocket_enabled', {})
|
691
|
+
HoverInfoLabelWidget(self.general_tab, text=ws_i18n.get('label', 'Websocket Enabled:'),
|
692
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"),
|
693
|
+
tooltip=ws_i18n.get('tooltip', '...'),
|
694
|
+
row=self.current_row, column=0)
|
695
|
+
ttk.Checkbutton(self.general_tab, variable=self.websocket_enabled_value, bootstyle="round-toggle").grid(
|
696
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
697
|
+
self.current_row += 1
|
698
|
+
|
699
|
+
clip_i18n = general_i18n.get('clipboard_enabled', {})
|
700
|
+
HoverInfoLabelWidget(self.general_tab, text=clip_i18n.get('label', 'Clipboard Enabled:'),
|
701
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"),
|
702
|
+
tooltip=clip_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
703
|
+
ttk.Checkbutton(self.general_tab, variable=self.clipboard_enabled_value, bootstyle="round-toggle").grid(
|
704
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
705
|
+
self.current_row += 1
|
706
|
+
|
707
|
+
both_i18n = general_i18n.get('allow_both_simultaneously', {})
|
708
|
+
HoverInfoLabelWidget(self.general_tab, text=both_i18n.get('label', 'Allow Both Simultaneously:'),
|
709
|
+
foreground="red", font=("Helvetica", 10, "bold"),
|
710
|
+
tooltip=both_i18n.get('tooltip', '...'),
|
711
|
+
row=self.current_row, column=0)
|
712
|
+
ttk.Checkbutton(self.general_tab, variable=self.use_both_clipboard_and_websocket_value, bootstyle="round-toggle").grid(
|
713
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
714
|
+
self.current_row += 1
|
715
|
+
|
716
|
+
merge_i18n = general_i18n.get('merge_sequential_text', {})
|
717
|
+
HoverInfoLabelWidget(self.general_tab, text=merge_i18n.get('label', 'Merge Matching Sequential Text:'),
|
718
|
+
foreground="red", font=("Helvetica", 10, "bold"),
|
719
|
+
tooltip=merge_i18n.get('tooltip', '...'),
|
720
|
+
row=self.current_row, column=0)
|
721
|
+
ttk.Checkbutton(self.general_tab, variable=self.merge_matching_sequential_text_value, bootstyle="round-toggle").grid(
|
722
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
723
|
+
self.current_row += 1
|
724
|
+
|
725
|
+
uri_i18n = general_i18n.get('websocket_uri', {})
|
726
|
+
HoverInfoLabelWidget(self.general_tab, text=uri_i18n.get('label', 'Websocket URI(s):'),
|
727
|
+
tooltip=uri_i18n.get('tooltip', '...'),
|
728
|
+
row=self.current_row, column=0)
|
729
|
+
ttk.Entry(self.general_tab, width=50, textvariable=self.websocket_uri_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
730
|
+
self.current_row += 1
|
731
|
+
|
732
|
+
regex_i18n = general_i18n.get('texthook_regex', {})
|
733
|
+
HoverInfoLabelWidget(self.general_tab, text=regex_i18n.get('label', 'TextHook Replacement Regex:'),
|
734
|
+
tooltip=regex_i18n.get('tooltip', '...'),
|
735
|
+
row=self.current_row, column=0)
|
736
|
+
ttk.Entry(self.general_tab, textvariable=self.texthook_replacement_regex_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
737
|
+
self.current_row += 1
|
738
|
+
|
739
|
+
open_config_i18n = general_i18n.get('open_config_on_startup', {})
|
740
|
+
HoverInfoLabelWidget(self.general_tab, text=open_config_i18n.get('label', 'Open Config on Startup:'),
|
741
|
+
tooltip=open_config_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
742
|
+
ttk.Checkbutton(self.general_tab, variable=self.open_config_on_startup_value, bootstyle="round-toggle").grid(
|
743
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
744
|
+
self.current_row += 1
|
745
|
+
|
746
|
+
open_texthooker_i18n = general_i18n.get('open_texthooker_on_startup', {})
|
747
|
+
HoverInfoLabelWidget(self.general_tab, text=open_texthooker_i18n.get('label', 'Open GSM Texthooker on Startup:'),
|
748
|
+
tooltip=open_texthooker_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
749
|
+
ttk.Checkbutton(self.general_tab, variable=self.open_multimine_on_startup_value, bootstyle="round-toggle").grid(
|
750
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
751
|
+
self.current_row += 1
|
752
|
+
|
753
|
+
port_i18n = general_i18n.get('texthooker_port', {})
|
754
|
+
HoverInfoLabelWidget(self.general_tab, text=port_i18n.get('label', 'GSM Texthooker Port:'),
|
755
|
+
tooltip=port_i18n.get('tooltip', '...'),
|
756
|
+
row=self.current_row, column=0)
|
757
|
+
ttk.Entry(self.general_tab, textvariable=self.texthooker_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
758
|
+
self.current_row += 1
|
759
|
+
|
760
|
+
# locale_i18n = general_i18n.get('locale', {})
|
761
|
+
# HoverInfoLabelWidget(self.general_tab, text=locale_i18n.get('label', 'Locale:'),
|
762
|
+
# tooltip=locale_i18n.get('tooltip', '...'),
|
763
|
+
# row=self.current_row, column=0)
|
764
|
+
# locale_combobox = ttk.Combobox(self.general_tab, textvariable=self.locale_value, values=[Locale.English.name, Locale.日本語.name, Locale.中文.name], state="readonly")
|
765
|
+
# locale_combobox.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
766
|
+
# locale_combobox.bind("<<ComboboxSelected>>", lambda e: self.change_locale())
|
767
|
+
# self.current_row += 1
|
768
|
+
|
769
|
+
lang_i18n = general_i18n.get('native_language', {})
|
770
|
+
HoverInfoLabelWidget(self.general_tab, text=lang_i18n.get('label', 'Native Language:'),
|
771
|
+
tooltip=lang_i18n.get('tooltip', '...'),
|
772
|
+
row=self.current_row, column=0)
|
773
|
+
ttk.Combobox(self.general_tab, textvariable=self.native_language_value, values=CommonLanguages.get_all_names_pretty(), state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
774
|
+
self.current_row += 1
|
775
|
+
|
776
|
+
legend_i18n = general_i18n.get('legend', {})
|
777
|
+
ttk.Label(self.general_tab, text=legend_i18n.get('important', '...'), foreground="dark orange",
|
778
|
+
font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2, sticky='W', pady=2)
|
779
|
+
self.current_row += 1
|
780
|
+
ttk.Label(self.general_tab, text=legend_i18n.get('advanced', '...'), foreground="red",
|
781
|
+
font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2, sticky='W', pady=2)
|
782
|
+
self.current_row += 1
|
783
|
+
ttk.Label(self.general_tab, text=legend_i18n.get('recommended', '...'), foreground="green",
|
784
|
+
font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2, sticky='W', pady=2)
|
785
|
+
self.current_row += 1
|
786
|
+
ttk.Label(self.general_tab,
|
787
|
+
text=legend_i18n.get('tooltip_info', '...'),
|
788
|
+
font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2, sticky='W', pady=2)
|
789
|
+
self.current_row += 1
|
790
|
+
|
791
|
+
if is_beangate:
|
792
|
+
ttk.Button(self.general_tab, text=self.i18n.get('buttons', {}).get('run_function', 'Run Function'), command=self.test_func, bootstyle="info").grid(
|
793
|
+
row=self.current_row, column=0, pady=5
|
794
|
+
)
|
795
|
+
self.current_row += 1
|
796
|
+
|
797
|
+
self.add_reset_button(self.general_tab, "general", self.current_row, column=0, recreate_tab=self.create_general_tab)
|
798
|
+
|
799
|
+
self.general_tab.grid_columnconfigure(0, weight=0)
|
800
|
+
self.general_tab.grid_columnconfigure(1, weight=0)
|
801
|
+
for row in range(self.current_row):
|
802
|
+
self.general_tab.grid_rowconfigure(row, minsize=30)
|
803
|
+
|
804
|
+
return self.general_tab
|
805
|
+
|
806
|
+
@new_tab
|
807
|
+
def create_required_settings_tab(self):
|
808
|
+
if self.required_settings_frame is None:
|
809
|
+
self.required_settings_frame = ttk.Frame(self.notebook, padding=15)
|
810
|
+
self.notebook.add(self.required_settings_frame, text=self.i18n.get('tabs', {}).get('key_settings', {}).get('title', 'Key Settings'))
|
811
|
+
else:
|
812
|
+
for widget in self.required_settings_frame.winfo_children():
|
813
|
+
widget.destroy()
|
814
|
+
required_settings_frame = self.required_settings_frame
|
815
|
+
|
816
|
+
simple_i18n = self.i18n.get('tabs', {}).get('simple', {})
|
817
|
+
|
818
|
+
# key_settings_i18n = simple_i18n.get('key_settings', {})
|
819
|
+
# HoverInfoLabelWidget(required_settings_frame, text=key_settings_i18n.get('label', 'Key Settings'),
|
820
|
+
# tooltip=key_settings_i18n.get('tooltip', "These settings are important..."),
|
821
|
+
# row=self.current_row, column=0, columnspan=4, font=("Helvetica", 12, "bold"))
|
822
|
+
# self.current_row += 1
|
823
|
+
|
824
|
+
# --- General Settings ---
|
825
|
+
general_i18n = self.i18n.get('tabs', {}).get('general', {})
|
826
|
+
input_frame = ttk.Frame(required_settings_frame)
|
827
|
+
input_frame.grid(row=self.current_row, column=0, columnspan=4, sticky='W', pady=2)
|
828
|
+
|
829
|
+
ws_i18n = general_i18n.get('websocket_enabled', {})
|
830
|
+
HoverInfoLabelWidget(input_frame, text=ws_i18n.get('label', '...'),
|
831
|
+
tooltip=ws_i18n.get('tooltip', '...'), row=0, column=0)
|
832
|
+
ttk.Checkbutton(input_frame, variable=self.websocket_enabled_value, bootstyle="round-toggle").grid(row=0, column=1, sticky='W', pady=2)
|
833
|
+
|
834
|
+
clip_i18n = general_i18n.get('clipboard_enabled', {})
|
835
|
+
HoverInfoLabelWidget(input_frame, text=clip_i18n.get('label', '...'),
|
836
|
+
tooltip=clip_i18n.get('tooltip', '...'), row=0, column=2, padx=5)
|
837
|
+
ttk.Checkbutton(input_frame, variable=self.clipboard_enabled_value, bootstyle="round-toggle").grid(row=0, column=3, sticky='W', pady=2)
|
838
|
+
self.current_row += 1
|
839
|
+
|
840
|
+
uri_i18n = general_i18n.get('websocket_uri', {})
|
841
|
+
HoverInfoLabelWidget(required_settings_frame, text=uri_i18n.get('label', '...'),
|
842
|
+
tooltip=uri_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
843
|
+
ttk.Entry(required_settings_frame, width=50, textvariable=self.websocket_uri_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
844
|
+
self.current_row += 1
|
845
|
+
|
846
|
+
locale_i18n = general_i18n.get('locale', {})
|
847
|
+
HoverInfoLabelWidget(required_settings_frame, text=locale_i18n.get('label', '...'),
|
848
|
+
tooltip=locale_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
849
|
+
locale_combobox_simple = ttk.Combobox(required_settings_frame, textvariable=self.locale_value, values=[Locale.English.name, Locale.日本語.name, Locale.中文.name], state="readonly")
|
850
|
+
locale_combobox_simple.grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
851
|
+
locale_combobox_simple.bind("<<ComboboxSelected>>", lambda e: self.change_locale())
|
852
|
+
self.current_row += 1
|
853
|
+
|
854
|
+
# --- Paths Settings ---
|
855
|
+
paths_i18n = self.i18n.get('tabs', {}).get('paths', {})
|
856
|
+
browse_text = self.i18n.get('buttons', {}).get('browse', 'Browse')
|
857
|
+
watch_i18n = paths_i18n.get('folder_to_watch', {})
|
858
|
+
HoverInfoLabelWidget(required_settings_frame, text=watch_i18n.get('label', '...'),
|
859
|
+
tooltip=watch_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
860
|
+
folder_watch_entry = ttk.Entry(required_settings_frame, width=50, textvariable=self.folder_to_watch_value)
|
861
|
+
folder_watch_entry.grid(row=self.current_row, column=1, columnspan=2, sticky='EW', pady=2)
|
862
|
+
ttk.Button(required_settings_frame, text=browse_text, command=lambda: self.browse_folder(folder_watch_entry),
|
863
|
+
bootstyle="outline").grid(row=self.current_row, column=3, padx=5, pady=2)
|
864
|
+
self.current_row += 1
|
865
|
+
|
866
|
+
# --- Anki Settings ---
|
867
|
+
anki_i18n = self.i18n.get('tabs', {}).get('anki', {})
|
868
|
+
sentence_i18n = anki_i18n.get('sentence_field', {})
|
869
|
+
HoverInfoLabelWidget(required_settings_frame, text=sentence_i18n.get('label', '...'),
|
870
|
+
tooltip=sentence_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
871
|
+
ttk.Entry(required_settings_frame, textvariable=self.sentence_field_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
872
|
+
self.current_row += 1
|
873
|
+
|
874
|
+
audio_i18n = anki_i18n.get('sentence_audio_field', {})
|
875
|
+
HoverInfoLabelWidget(required_settings_frame, text=audio_i18n.get('label', '...'),
|
876
|
+
tooltip=audio_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
877
|
+
ttk.Entry(required_settings_frame, textvariable=self.sentence_audio_field_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
878
|
+
self.current_row += 1
|
879
|
+
|
880
|
+
pic_i18n = anki_i18n.get('picture_field', {})
|
881
|
+
HoverInfoLabelWidget(required_settings_frame, text=pic_i18n.get('label', '...'),
|
882
|
+
tooltip=pic_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
883
|
+
ttk.Entry(required_settings_frame, textvariable=self.picture_field_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
884
|
+
self.current_row += 1
|
885
|
+
|
886
|
+
word_i18n = anki_i18n.get('word_field', {})
|
887
|
+
HoverInfoLabelWidget(required_settings_frame, text=word_i18n.get('label', '...'),
|
888
|
+
tooltip=word_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
889
|
+
ttk.Entry(required_settings_frame, textvariable=self.word_field_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
890
|
+
self.current_row += 1
|
891
|
+
|
892
|
+
# --- Audio Settings ---
|
893
|
+
audio_tab_i18n = self.i18n.get('tabs', {}).get('audio', {})
|
894
|
+
begin_offset_i18n = audio_tab_i18n.get('beginning_offset', {})
|
895
|
+
HoverInfoLabelWidget(required_settings_frame, text=begin_offset_i18n.get('label', '...'),
|
896
|
+
tooltip=begin_offset_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
897
|
+
ttk.Entry(required_settings_frame, textvariable=self.beginning_offset_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
898
|
+
self.current_row += 1
|
899
|
+
|
900
|
+
# Vad end offset
|
901
|
+
|
902
|
+
vad_i18n = self.i18n.get('tabs', {}).get('vad', {})
|
903
|
+
vad_end_offset_i18n = vad_i18n.get('audio_end_offset', {})
|
904
|
+
HoverInfoLabelWidget(required_settings_frame, text=vad_end_offset_i18n.get('label', '...'),
|
905
|
+
tooltip=vad_end_offset_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
906
|
+
ttk.Entry(required_settings_frame, textvariable=self.end_offset_value).grid(row=self.current_row, column=1, columnspan=3, sticky='EW', pady=2)
|
907
|
+
self.current_row += 1
|
908
|
+
|
909
|
+
# --- Features Settings ---
|
910
|
+
features_i18n = self.i18n.get('tabs', {}).get('features', {})
|
911
|
+
# action_frame = ttk.Frame(required_settings_frame)
|
912
|
+
# action_frame.grid(row=self.current_row, column=0, columnspan=4, sticky='W', pady=2)
|
913
|
+
|
914
|
+
# Feature Toggles, Anki, OBS, Audio, VAD, AI, WIP
|
915
|
+
feature_frame = ttk.Frame(required_settings_frame)
|
916
|
+
feature_frame.grid(row=self.current_row, column=0, columnspan=5, sticky='W', pady=2)
|
917
|
+
|
918
|
+
# anki_enabled_i18n = simple_i18n.get('anki_enabled', {})
|
919
|
+
# HoverInfoLabelWidget(feature_frame, text=anki_enabled_i18n.get('label', '...'),
|
920
|
+
# tooltip=anki_enabled_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
921
|
+
# ttk.Checkbutton(feature_frame, variable=self.update_anki_value, bootstyle="round-toggle").grid(
|
922
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
923
|
+
|
924
|
+
open_edit_i18n = features_i18n.get('open_anki_edit', {})
|
925
|
+
HoverInfoLabelWidget(feature_frame, text=open_edit_i18n.get('label', '...'),
|
926
|
+
tooltip=open_edit_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
927
|
+
ttk.Checkbutton(feature_frame, variable=self.open_anki_edit_value, bootstyle="round-toggle").grid(
|
928
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
929
|
+
|
930
|
+
open_browser_i18n = features_i18n.get('open_anki_browser', {})
|
931
|
+
HoverInfoLabelWidget(feature_frame, text=open_browser_i18n.get('label', '...'),
|
932
|
+
tooltip=open_browser_i18n.get('tooltip', '...'), row=self.current_row, column=2, padx=5)
|
933
|
+
ttk.Checkbutton(feature_frame, variable=self.open_anki_browser_value, bootstyle="round-toggle").grid(
|
934
|
+
row=self.current_row, column=3, sticky='W', pady=2)
|
935
|
+
self.current_row += 1
|
936
|
+
|
937
|
+
# obs_enabled_i18n = simple_i18n.get('obs_enabled', {})
|
938
|
+
# HoverInfoLabelWidget(feature_frame, text=obs_enabled_i18n.get('label', '...'),
|
939
|
+
# tooltip=obs_enabled_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
940
|
+
# ttk.Checkbutton(feature_frame, variable=self.obs_enabled_value, bootstyle="round-toggle").grid(
|
941
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
942
|
+
# self.current_row += 1
|
943
|
+
|
944
|
+
# screenshot_i18n = simple_i18n.get('screenshot_enabled', {})
|
945
|
+
# HoverInfoLabelWidget(feature_frame, text=screenshot_i18n.get('label', '...'),
|
946
|
+
# tooltip=screenshot_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
947
|
+
# ttk.Checkbutton(feature_frame, variable=self.screenshot_enabled_value, bootstyle="round-toggle").grid(
|
948
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
949
|
+
# self.current_row += 1
|
950
|
+
|
951
|
+
# audio_i18n = self.i18n.get('tabs', {}).get('audio', {})
|
952
|
+
# audio_enabled_i18n = simple_i18n.get('audio_enabled', {})
|
953
|
+
# HoverInfoLabelWidget(feature_frame, text=audio_enabled_i18n.get('label', '...'),
|
954
|
+
# tooltip=audio_enabled_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
955
|
+
# ttk.Checkbutton(feature_frame, variable=self.audio_enabled_value, bootstyle="round-toggle").grid(
|
956
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
957
|
+
# self.current_row += 1
|
958
|
+
|
959
|
+
# vad_i18n = self.i18n.get('tabs', {}).get('vad', {})
|
960
|
+
# vad_enabled_i18n = simple_i18n.get('vad_enabled', {})
|
961
|
+
# HoverInfoLabelWidget(feature_frame, text=vad_enabled_i18n.get('label', '...'),
|
962
|
+
# tooltip=vad_enabled_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
963
|
+
# ttk.Checkbutton(feature_frame, variable=self.do_vad_postprocessing_value, bootstyle="round-toggle").grid(
|
964
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
965
|
+
# self.current_row += 1
|
966
|
+
|
967
|
+
# ai_i18n = self.i18n.get('tabs', {}).get('ai', {})
|
968
|
+
# ai_enabled_i18n = simple_i18n.get('ai_enabled', {})
|
969
|
+
# HoverInfoLabelWidget(feature_frame, text=ai_enabled_i18n.get('label', '...'),
|
970
|
+
# tooltip=ai_enabled_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
971
|
+
# ttk.Checkbutton(feature_frame, variable=self.ai_enabled_value, bootstyle="round-toggle").grid(
|
972
|
+
# row=self.current_row, column=1, sticky='W', pady=2)
|
973
|
+
|
974
|
+
required_settings_frame.grid_columnconfigure(1, weight=1)
|
975
|
+
|
976
|
+
return required_settings_frame
|
977
|
+
|
978
|
+
@new_tab
|
979
|
+
def create_vad_tab(self):
|
980
|
+
if self.vad_tab is None:
|
981
|
+
vad_i18n = self.i18n.get('tabs', {}).get('vad', {})
|
982
|
+
self.vad_tab = ttk.Frame(self.notebook, padding=15)
|
983
|
+
self.notebook.add(self.vad_tab, text=vad_i18n.get('title', 'VAD'))
|
984
|
+
else:
|
985
|
+
for widget in self.vad_tab.winfo_children():
|
986
|
+
widget.destroy()
|
987
|
+
|
988
|
+
vad_frame = self.vad_tab
|
989
|
+
vad_i18n = self.i18n.get('tabs', {}).get('vad', {})
|
990
|
+
|
991
|
+
postproc_i18n = vad_i18n.get('do_postprocessing', {})
|
992
|
+
HoverInfoLabelWidget(vad_frame, text=postproc_i18n.get('label', '...'),
|
993
|
+
tooltip=postproc_i18n.get('tooltip', '...'),
|
994
|
+
row=self.current_row, column=0)
|
995
|
+
ttk.Checkbutton(vad_frame, variable=self.do_vad_postprocessing_value, bootstyle="round-toggle").grid(
|
996
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
997
|
+
self.current_row += 1
|
998
|
+
|
999
|
+
lang_i18n = vad_i18n.get('language', {})
|
1000
|
+
HoverInfoLabelWidget(vad_frame, text=lang_i18n.get('label', '...'),
|
1001
|
+
tooltip=lang_i18n.get('tooltip', '...'),
|
1002
|
+
row=self.current_row, column=0)
|
1003
|
+
ttk.Combobox(vad_frame, textvariable=self.language_value, values=AVAILABLE_LANGUAGES, state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1004
|
+
self.current_row += 1
|
1005
|
+
|
1006
|
+
whisper_i18n = vad_i18n.get('whisper_model', {})
|
1007
|
+
HoverInfoLabelWidget(vad_frame, text=whisper_i18n.get('label', '...'), tooltip=whisper_i18n.get('tooltip', '...'),
|
1008
|
+
row=self.current_row, column=0)
|
1009
|
+
ttk.Combobox(vad_frame, textvariable=self.whisper_model_value, values=[WHISPER_TINY, WHISPER_BASE, WHISPER_SMALL, WHISPER_MEDIUM,
|
1010
|
+
WHSIPER_LARGE, WHISPER_TURBO], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1011
|
+
self.current_row += 1
|
1012
|
+
|
1013
|
+
selected_model_i18n = vad_i18n.get('selected_model', {})
|
1014
|
+
HoverInfoLabelWidget(vad_frame, text=selected_model_i18n.get('label', '...'), tooltip=selected_model_i18n.get('tooltip', '...'),
|
1015
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1016
|
+
ttk.Combobox(vad_frame, textvariable=self.selected_vad_model_value, values=[SILERO, WHISPER], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1017
|
+
self.current_row += 1
|
1018
|
+
|
1019
|
+
backup_model_i18n = vad_i18n.get('backup_model', {})
|
1020
|
+
HoverInfoLabelWidget(vad_frame, text=backup_model_i18n.get('label', '...'),
|
1021
|
+
tooltip=backup_model_i18n.get('tooltip', '...'),
|
1022
|
+
row=self.current_row, column=0)
|
1023
|
+
ttk.Combobox(vad_frame, textvariable=self.backup_vad_model_value, values=[OFF, SILERO, WHISPER], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1024
|
+
self.current_row += 1
|
1025
|
+
|
1026
|
+
no_results_i18n = vad_i18n.get('add_on_no_results', {})
|
1027
|
+
HoverInfoLabelWidget(vad_frame, text=no_results_i18n.get('label', '...'),
|
1028
|
+
tooltip=no_results_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1029
|
+
ttk.Checkbutton(vad_frame, variable=self.add_audio_on_no_results_value, bootstyle="round-toggle").grid(
|
1030
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1031
|
+
self.current_row += 1
|
1032
|
+
|
1033
|
+
end_offset_i18n = vad_i18n.get('audio_end_offset', {})
|
1034
|
+
HoverInfoLabelWidget(vad_frame, text=end_offset_i18n.get('label', '...'),
|
1035
|
+
tooltip=end_offset_i18n.get('tooltip', '...'), foreground="dark orange",
|
1036
|
+
font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1037
|
+
ttk.Entry(vad_frame, textvariable=self.end_offset_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1038
|
+
self.current_row += 1
|
1039
|
+
|
1040
|
+
trim_begin_i18n = vad_i18n.get('trim_beginning', {})
|
1041
|
+
HoverInfoLabelWidget(vad_frame, text=trim_begin_i18n.get('label', '...'),
|
1042
|
+
tooltip=trim_begin_i18n.get('tooltip', '...'),
|
1043
|
+
row=self.current_row, column=0)
|
1044
|
+
ttk.Checkbutton(vad_frame, variable=self.vad_trim_beginning_value, bootstyle="round-toggle").grid(
|
1045
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1046
|
+
|
1047
|
+
begin_offset_i18n = vad_i18n.get('beginning_offset', {})
|
1048
|
+
HoverInfoLabelWidget(vad_frame, text=begin_offset_i18n.get('label', '...'),
|
1049
|
+
tooltip=begin_offset_i18n.get('tooltip', '...'),
|
1050
|
+
row=self.current_row, column=2)
|
1051
|
+
ttk.Entry(vad_frame, textvariable=self.vad_beginning_offset_value).grid(row=self.current_row, column=3, sticky='EW', pady=2)
|
1052
|
+
self.current_row += 1
|
1053
|
+
|
1054
|
+
splice_i18n = vad_i18n.get('cut_and_splice', {})
|
1055
|
+
HoverInfoLabelWidget(vad_frame, text=splice_i18n.get('label', '...'),
|
1056
|
+
tooltip=splice_i18n.get('tooltip', '...'),
|
1057
|
+
row=self.current_row, column=0)
|
1058
|
+
ttk.Checkbutton(vad_frame, variable=self.cut_and_splice_segments_value, bootstyle="round-toggle").grid(
|
1059
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1060
|
+
|
1061
|
+
padding_i18n = vad_i18n.get('splice_padding', {})
|
1062
|
+
HoverInfoLabelWidget(vad_frame, text=padding_i18n.get('label', '...'),
|
1063
|
+
tooltip=padding_i18n.get('tooltip', '...'),
|
1064
|
+
row=self.current_row, column=2)
|
1065
|
+
ttk.Entry(vad_frame, textvariable=self.splice_padding_value).grid(row=self.current_row, column=3, sticky='EW', pady=2)
|
1066
|
+
self.current_row += 1
|
1067
|
+
|
1068
|
+
self.add_reset_button(vad_frame, "vad", self.current_row, 0, self.create_vad_tab)
|
1069
|
+
|
1070
|
+
for col in range(5): vad_frame.grid_columnconfigure(col, weight=0)
|
1071
|
+
for row in range(self.current_row): vad_frame.grid_rowconfigure(row, minsize=30)
|
1072
|
+
|
1073
|
+
return vad_frame
|
1074
|
+
|
1075
|
+
@new_tab
|
1076
|
+
def create_paths_tab(self):
|
1077
|
+
if self.paths_tab is None:
|
1078
|
+
paths_i18n = self.i18n.get('tabs', {}).get('paths', {})
|
1079
|
+
self.paths_tab = ttk.Frame(self.notebook, padding=15)
|
1080
|
+
self.notebook.add(self.paths_tab, text=paths_i18n.get('title', 'Paths'))
|
1081
|
+
else:
|
1082
|
+
for widget in self.paths_tab.winfo_children():
|
1083
|
+
widget.destroy()
|
1084
|
+
|
1085
|
+
paths_frame = self.paths_tab
|
1086
|
+
paths_i18n = self.i18n.get('tabs', {}).get('paths', {})
|
1087
|
+
browse_text = self.i18n.get('buttons', {}).get('browse', 'Browse')
|
1088
|
+
|
1089
|
+
watch_i18n = paths_i18n.get('folder_to_watch', {})
|
1090
|
+
HoverInfoLabelWidget(paths_frame, text=watch_i18n.get('label', '...'), tooltip=watch_i18n.get('tooltip', '...'),
|
1091
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1092
|
+
folder_watch_entry = ttk.Entry(paths_frame, width=50, textvariable=self.folder_to_watch_value)
|
1093
|
+
folder_watch_entry.grid(row=self.current_row, column=1, sticky='W', pady=2)
|
1094
|
+
ttk.Button(paths_frame, text=browse_text, command=lambda: self.browse_folder(folder_watch_entry),
|
1095
|
+
bootstyle="outline").grid(row=self.current_row, column=2, padx=5, pady=2)
|
1096
|
+
self.current_row += 1
|
1097
|
+
|
1098
|
+
audio_dest_i18n = paths_i18n.get('audio_destination', {})
|
1099
|
+
HoverInfoLabelWidget(paths_frame, text=audio_dest_i18n.get('label', '...'), tooltip=audio_dest_i18n.get('tooltip', '...'),
|
1100
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1101
|
+
audio_dest_entry = ttk.Entry(paths_frame, width=50, textvariable=self.audio_destination_value)
|
1102
|
+
audio_dest_entry.grid(row=self.current_row, column=1, sticky='W', pady=2)
|
1103
|
+
ttk.Button(paths_frame, text=browse_text, command=lambda: self.browse_folder(audio_dest_entry),
|
1104
|
+
bootstyle="outline").grid(row=self.current_row, column=2, padx=5, pady=2)
|
1105
|
+
self.current_row += 1
|
1106
|
+
|
1107
|
+
ss_dest_i18n = paths_i18n.get('screenshot_destination', {})
|
1108
|
+
HoverInfoLabelWidget(paths_frame, text=ss_dest_i18n.get('label', '...'),
|
1109
|
+
tooltip=ss_dest_i18n.get('tooltip', '...'), foreground="dark orange",
|
1110
|
+
font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1111
|
+
ss_dest_entry = ttk.Entry(paths_frame, width=50, textvariable=self.screenshot_destination_value)
|
1112
|
+
ss_dest_entry.grid(row=self.current_row, column=1, sticky='W', pady=2)
|
1113
|
+
ttk.Button(paths_frame, text=browse_text, command=lambda: self.browse_folder(ss_dest_entry),
|
1114
|
+
bootstyle="outline").grid(row=self.current_row, column=2, padx=5, pady=2)
|
1115
|
+
self.current_row += 1
|
1116
|
+
|
1117
|
+
rm_vid_i18n = paths_i18n.get('remove_video', {})
|
1118
|
+
HoverInfoLabelWidget(paths_frame, text=rm_vid_i18n.get('label', '...'), tooltip=rm_vid_i18n.get('tooltip', '...'),
|
1119
|
+
row=self.current_row, column=0)
|
1120
|
+
ttk.Checkbutton(paths_frame, variable=self.remove_video_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1121
|
+
column=1, sticky='W', pady=2)
|
1122
|
+
self.current_row += 1
|
1123
|
+
|
1124
|
+
rm_audio_i18n = paths_i18n.get('remove_audio', {})
|
1125
|
+
HoverInfoLabelWidget(paths_frame, text=rm_audio_i18n.get('label', '...'), tooltip=rm_audio_i18n.get('tooltip', '...'),
|
1126
|
+
row=self.current_row, column=0)
|
1127
|
+
ttk.Checkbutton(paths_frame, variable=self.remove_audio_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1128
|
+
column=1, sticky='W', pady=2)
|
1129
|
+
self.current_row += 1
|
1130
|
+
|
1131
|
+
rm_ss_i18n = paths_i18n.get('remove_screenshot', {})
|
1132
|
+
HoverInfoLabelWidget(paths_frame, text=rm_ss_i18n.get('label', '...'), tooltip=rm_ss_i18n.get('tooltip', '...'),
|
1133
|
+
row=self.current_row, column=0)
|
1134
|
+
ttk.Checkbutton(paths_frame, variable=self.remove_screenshot_value, bootstyle="round-toggle").grid(
|
1135
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1136
|
+
self.current_row += 1
|
1137
|
+
|
1138
|
+
self.add_reset_button(paths_frame, "paths", self.current_row, 0, self.create_paths_tab)
|
1139
|
+
|
1140
|
+
for col in range(3): paths_frame.grid_columnconfigure(col, weight=0)
|
1141
|
+
for row in range(self.current_row): paths_frame.grid_rowconfigure(row, minsize=30)
|
1142
|
+
|
1143
|
+
return paths_frame
|
1144
|
+
|
1145
|
+
def browse_file(self, entry_widget):
|
1146
|
+
file_selected = filedialog.askopenfilename()
|
1147
|
+
if file_selected:
|
1148
|
+
# The entry widget's textvariable will be updated automatically
|
1149
|
+
entry_widget.delete(0, tk.END)
|
1150
|
+
entry_widget.insert(0, file_selected)
|
1151
|
+
|
1152
|
+
def browse_folder(self, entry_widget):
|
1153
|
+
folder_selected = filedialog.askdirectory()
|
1154
|
+
if folder_selected:
|
1155
|
+
# The entry widget's textvariable will be updated automatically
|
1156
|
+
entry_widget.delete(0, tk.END)
|
1157
|
+
entry_widget.insert(0, folder_selected)
|
1158
|
+
|
1159
|
+
@new_tab
|
1160
|
+
def create_anki_tab(self):
|
1161
|
+
if self.anki_tab is None:
|
1162
|
+
anki_i18n = self.i18n.get('tabs', {}).get('anki', {})
|
1163
|
+
self.anki_tab = ttk.Frame(self.notebook, padding=15)
|
1164
|
+
self.notebook.add(self.anki_tab, text=anki_i18n.get('title', 'Anki'))
|
1165
|
+
else:
|
1166
|
+
for widget in self.anki_tab.winfo_children():
|
1167
|
+
widget.destroy()
|
1168
|
+
|
1169
|
+
anki_frame = self.anki_tab
|
1170
|
+
anki_i18n = self.i18n.get('tabs', {}).get('anki', {})
|
1171
|
+
|
1172
|
+
update_i18n = anki_i18n.get('update_anki', {})
|
1173
|
+
HoverInfoLabelWidget(anki_frame, text=update_i18n.get('label', '...'), tooltip=update_i18n.get('tooltip', '...'),
|
1174
|
+
row=self.current_row, column=0)
|
1175
|
+
ttk.Checkbutton(anki_frame, variable=self.update_anki_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1176
|
+
column=1, sticky='W', pady=2)
|
1177
|
+
self.current_row += 1
|
1178
|
+
|
1179
|
+
url_i18n = anki_i18n.get('url', {})
|
1180
|
+
HoverInfoLabelWidget(anki_frame, text=url_i18n.get('label', '...'), tooltip=url_i18n.get('tooltip', '...'),
|
1181
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1182
|
+
ttk.Entry(anki_frame, width=50, textvariable=self.anki_url_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1183
|
+
self.current_row += 1
|
1184
|
+
|
1185
|
+
sentence_i18n = anki_i18n.get('sentence_field', {})
|
1186
|
+
HoverInfoLabelWidget(anki_frame, text=sentence_i18n.get('label', '...'), tooltip=sentence_i18n.get('tooltip', '...'),
|
1187
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1188
|
+
ttk.Entry(anki_frame, textvariable=self.sentence_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1189
|
+
self.current_row += 1
|
1190
|
+
|
1191
|
+
audio_i18n = anki_i18n.get('sentence_audio_field', {})
|
1192
|
+
HoverInfoLabelWidget(anki_frame, text=audio_i18n.get('label', '...'),
|
1193
|
+
tooltip=audio_i18n.get('tooltip', '...'),
|
1194
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1195
|
+
ttk.Entry(anki_frame, textvariable=self.sentence_audio_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1196
|
+
self.current_row += 1
|
1197
|
+
|
1198
|
+
pic_i18n = anki_i18n.get('picture_field', {})
|
1199
|
+
HoverInfoLabelWidget(anki_frame, text=pic_i18n.get('label', '...'), tooltip=pic_i18n.get('tooltip', '...'),
|
1200
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1201
|
+
ttk.Entry(anki_frame, textvariable=self.picture_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1202
|
+
self.current_row += 1
|
1203
|
+
|
1204
|
+
word_i18n = anki_i18n.get('word_field', {})
|
1205
|
+
HoverInfoLabelWidget(anki_frame, text=word_i18n.get('label', '...'), tooltip=word_i18n.get('tooltip', '...'),
|
1206
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1207
|
+
ttk.Entry(anki_frame, textvariable=self.word_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1208
|
+
self.current_row += 1
|
1209
|
+
|
1210
|
+
prev_sent_i18n = anki_i18n.get('previous_sentence_field', {})
|
1211
|
+
HoverInfoLabelWidget(anki_frame, text=prev_sent_i18n.get('label', '...'),
|
1212
|
+
tooltip=prev_sent_i18n.get('tooltip', '...'),
|
1213
|
+
row=self.current_row, column=0)
|
1214
|
+
ttk.Entry(anki_frame, textvariable=self.previous_sentence_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1215
|
+
self.current_row += 1
|
1216
|
+
|
1217
|
+
prev_img_i18n = anki_i18n.get('previous_image_field', {})
|
1218
|
+
HoverInfoLabelWidget(anki_frame, text=prev_img_i18n.get('label', '...'),
|
1219
|
+
tooltip=prev_img_i18n.get('tooltip', '...'),
|
1220
|
+
row=self.current_row, column=0)
|
1221
|
+
ttk.Entry(anki_frame, textvariable=self.previous_image_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1222
|
+
self.current_row += 1
|
1223
|
+
|
1224
|
+
tags_i18n = anki_i18n.get('custom_tags', {})
|
1225
|
+
HoverInfoLabelWidget(anki_frame, text=tags_i18n.get('label', '...'), tooltip=tags_i18n.get('tooltip', '...'),
|
1226
|
+
row=self.current_row, column=0)
|
1227
|
+
ttk.Entry(anki_frame, width=50, textvariable=self.custom_tags_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1228
|
+
self.current_row += 1
|
1229
|
+
|
1230
|
+
tags_check_i18n = anki_i18n.get('tags_to_check', {})
|
1231
|
+
HoverInfoLabelWidget(anki_frame, text=tags_check_i18n.get('label', '...'),
|
1232
|
+
tooltip=tags_check_i18n.get('tooltip', '...'),
|
1233
|
+
foreground="green", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1234
|
+
ttk.Entry(anki_frame, width=50, textvariable=self.tags_to_check_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1235
|
+
self.current_row += 1
|
1236
|
+
|
1237
|
+
game_tag_i18n = anki_i18n.get('add_game_tag', {})
|
1238
|
+
HoverInfoLabelWidget(anki_frame, text=game_tag_i18n.get('label', '...'),
|
1239
|
+
tooltip=game_tag_i18n.get('tooltip', '...'), foreground="green",
|
1240
|
+
font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1241
|
+
ttk.Checkbutton(anki_frame, variable=self.add_game_tag_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1242
|
+
column=1, sticky='W', pady=2)
|
1243
|
+
self.current_row += 1
|
1244
|
+
|
1245
|
+
parent_tag_i18n = anki_i18n.get('parent_tag', {})
|
1246
|
+
HoverInfoLabelWidget(anki_frame, text=parent_tag_i18n.get('label', '...'),
|
1247
|
+
foreground="green", font=("Helvetica", 10, "bold"),
|
1248
|
+
tooltip=parent_tag_i18n.get('tooltip', '...'),
|
1249
|
+
row=self.current_row, column=0)
|
1250
|
+
ttk.Entry(anki_frame, width=50, textvariable=self.parent_tag_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1251
|
+
self.current_row += 1
|
1252
|
+
|
1253
|
+
ow_audio_i18n = anki_i18n.get('overwrite_audio', {})
|
1254
|
+
HoverInfoLabelWidget(anki_frame, text=ow_audio_i18n.get('label', '...'), tooltip=ow_audio_i18n.get('tooltip', '...'),
|
1255
|
+
row=self.current_row, column=0)
|
1256
|
+
ttk.Checkbutton(anki_frame, variable=self.overwrite_audio_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1257
|
+
column=1, sticky='W', pady=2)
|
1258
|
+
self.current_row += 1
|
1259
|
+
|
1260
|
+
ow_pic_i18n = anki_i18n.get('overwrite_picture', {})
|
1261
|
+
HoverInfoLabelWidget(anki_frame, text=ow_pic_i18n.get('label', '...'),
|
1262
|
+
tooltip=ow_pic_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1263
|
+
ttk.Checkbutton(anki_frame, variable=self.overwrite_picture_value, bootstyle="round-toggle").grid(
|
1264
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1265
|
+
self.current_row += 1
|
1266
|
+
|
1267
|
+
multi_ow_i18n = anki_i18n.get('multi_overwrites_sentence', {})
|
1268
|
+
HoverInfoLabelWidget(anki_frame, text=multi_ow_i18n.get('label', '...'),
|
1269
|
+
tooltip=multi_ow_i18n.get('tooltip', '...'),
|
1270
|
+
row=self.current_row, column=0)
|
1271
|
+
ttk.Checkbutton(anki_frame, variable=self.multi_overwrites_sentence_value, bootstyle="round-toggle").grid(
|
1272
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1273
|
+
self.current_row += 1
|
1274
|
+
|
1275
|
+
self.add_reset_button(anki_frame, "anki", self.current_row, 0, self.create_anki_tab)
|
1276
|
+
|
1277
|
+
for col in range(2): anki_frame.grid_columnconfigure(col, weight=0)
|
1278
|
+
for row in range(self.current_row): anki_frame.grid_rowconfigure(row, minsize=30)
|
1279
|
+
|
1280
|
+
return anki_frame
|
1281
|
+
|
1282
|
+
def on_profiles_tab_selected(self, event):
|
1283
|
+
try:
|
1284
|
+
profiles_i18n = self.i18n.get('tabs', {}).get('profiles', {})
|
1285
|
+
if self.window.state() != "withdrawn" and self.notebook.tab(self.notebook.select(), "text") == profiles_i18n.get('title', 'Profiles'):
|
1286
|
+
self.refresh_obs_scenes()
|
1287
|
+
except Exception as e:
|
1288
|
+
logger.debug(e)
|
1289
|
+
|
1290
|
+
@new_tab
|
1291
|
+
def create_features_tab(self):
|
1292
|
+
if self.features_tab is None:
|
1293
|
+
features_i18n = self.i18n.get('tabs', {}).get('features', {})
|
1294
|
+
self.features_tab = ttk.Frame(self.notebook, padding=15)
|
1295
|
+
self.notebook.add(self.features_tab, text=features_i18n.get('title', 'Features'))
|
1296
|
+
else:
|
1297
|
+
for widget in self.features_tab.winfo_children():
|
1298
|
+
widget.destroy()
|
1299
|
+
|
1300
|
+
features_frame = self.features_tab
|
1301
|
+
features_i18n = self.i18n.get('tabs', {}).get('features', {})
|
1302
|
+
|
1303
|
+
notify_i18n = features_i18n.get('notify_on_update', {})
|
1304
|
+
HoverInfoLabelWidget(features_frame, text=notify_i18n.get('label', '...'), tooltip=notify_i18n.get('tooltip', '...'),
|
1305
|
+
row=self.current_row, column=0)
|
1306
|
+
ttk.Checkbutton(features_frame, variable=self.notify_on_update_value, bootstyle="round-toggle").grid(
|
1307
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1308
|
+
self.current_row += 1
|
1309
|
+
|
1310
|
+
open_edit_i18n = features_i18n.get('open_anki_edit', {})
|
1311
|
+
HoverInfoLabelWidget(features_frame, text=open_edit_i18n.get('label', '...'),
|
1312
|
+
tooltip=open_edit_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1313
|
+
ttk.Checkbutton(features_frame, variable=self.open_anki_edit_value, bootstyle="round-toggle").grid(
|
1314
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1315
|
+
self.current_row += 1
|
1316
|
+
|
1317
|
+
open_browser_i18n = features_i18n.get('open_anki_browser', {})
|
1318
|
+
HoverInfoLabelWidget(features_frame, text=open_browser_i18n.get('label', '...'),
|
1319
|
+
tooltip=open_browser_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1320
|
+
ttk.Checkbutton(features_frame, variable=self.open_anki_browser_value, bootstyle="round-toggle").grid(
|
1321
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1322
|
+
self.current_row += 1
|
1323
|
+
|
1324
|
+
query_i18n = features_i18n.get('browser_query', {})
|
1325
|
+
HoverInfoLabelWidget(features_frame, text=query_i18n.get('label', '...'),
|
1326
|
+
tooltip=query_i18n.get('tooltip', '...'),
|
1327
|
+
row=self.current_row, column=0)
|
1328
|
+
ttk.Entry(features_frame, width=50, textvariable=self.browser_query_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1329
|
+
self.current_row += 1
|
1330
|
+
|
1331
|
+
backfill_i18n = features_i18n.get('backfill_audio', {})
|
1332
|
+
HoverInfoLabelWidget(features_frame, text=backfill_i18n.get('label', '...'), tooltip=backfill_i18n.get('tooltip', '...'),
|
1333
|
+
row=self.current_row, column=0)
|
1334
|
+
ttk.Checkbutton(features_frame, variable=self.backfill_audio_value, bootstyle="round-toggle").grid(
|
1335
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1336
|
+
self.current_row += 1
|
1337
|
+
|
1338
|
+
full_auto_i18n = features_i18n.get('full_auto', {})
|
1339
|
+
HoverInfoLabelWidget(features_frame, text=full_auto_i18n.get('label', '...'), tooltip=full_auto_i18n.get('tooltip', '...'),
|
1340
|
+
row=self.current_row, column=0)
|
1341
|
+
ttk.Checkbutton(features_frame, variable=self.full_auto_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1342
|
+
column=1, sticky='W', pady=2)
|
1343
|
+
self.current_row += 1
|
1344
|
+
|
1345
|
+
self.add_reset_button(features_frame, "features", self.current_row, 0, self.create_features_tab)
|
1346
|
+
|
1347
|
+
for col in range(3): features_frame.grid_columnconfigure(col, weight=0)
|
1348
|
+
for row in range(self.current_row): features_frame.grid_rowconfigure(row, minsize=30)
|
1349
|
+
|
1350
|
+
return features_frame
|
1351
|
+
|
1352
|
+
@new_tab
|
1353
|
+
def create_screenshot_tab(self):
|
1354
|
+
if self.screenshot_tab is None:
|
1355
|
+
ss_i18n = self.i18n.get('tabs', {}).get('screenshot', {})
|
1356
|
+
self.screenshot_tab = ttk.Frame(self.notebook, padding=15)
|
1357
|
+
self.notebook.add(self.screenshot_tab, text=ss_i18n.get('title', 'Screenshot'))
|
1358
|
+
else:
|
1359
|
+
for widget in self.screenshot_tab.winfo_children():
|
1360
|
+
widget.destroy()
|
1361
|
+
|
1362
|
+
screenshot_frame = self.screenshot_tab
|
1363
|
+
ss_i18n = self.i18n.get('tabs', {}).get('screenshot', {})
|
1364
|
+
|
1365
|
+
enabled_i18n = ss_i18n.get('enabled', {})
|
1366
|
+
HoverInfoLabelWidget(screenshot_frame, text=enabled_i18n.get('label', '...'), tooltip=enabled_i18n.get('tooltip', '...'),
|
1367
|
+
row=self.current_row, column=0)
|
1368
|
+
ttk.Checkbutton(screenshot_frame, variable=self.screenshot_enabled_value, bootstyle="round-toggle").grid(
|
1369
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1370
|
+
self.current_row += 1
|
1371
|
+
|
1372
|
+
width_i18n = ss_i18n.get('width', {})
|
1373
|
+
HoverInfoLabelWidget(screenshot_frame, text=width_i18n.get('label', '...'), tooltip=width_i18n.get('tooltip', '...'),
|
1374
|
+
row=self.current_row, column=0)
|
1375
|
+
ttk.Entry(screenshot_frame, textvariable=self.screenshot_width_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1376
|
+
self.current_row += 1
|
1377
|
+
|
1378
|
+
height_i18n = ss_i18n.get('height', {})
|
1379
|
+
HoverInfoLabelWidget(screenshot_frame, text=height_i18n.get('label', '...'), tooltip=height_i18n.get('tooltip', '...'),
|
1380
|
+
row=self.current_row, column=0)
|
1381
|
+
ttk.Entry(screenshot_frame, textvariable=self.screenshot_height_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1382
|
+
self.current_row += 1
|
1383
|
+
|
1384
|
+
quality_i18n = ss_i18n.get('quality', {})
|
1385
|
+
HoverInfoLabelWidget(screenshot_frame, text=quality_i18n.get('label', '...'), tooltip=quality_i18n.get('tooltip', '...'),
|
1386
|
+
row=self.current_row, column=0)
|
1387
|
+
ttk.Entry(screenshot_frame, textvariable=self.screenshot_quality_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1388
|
+
self.current_row += 1
|
1389
|
+
|
1390
|
+
ext_i18n = ss_i18n.get('extension', {})
|
1391
|
+
HoverInfoLabelWidget(screenshot_frame, text=ext_i18n.get('label', '...'), tooltip=ext_i18n.get('tooltip', '...'),
|
1392
|
+
row=self.current_row, column=0)
|
1393
|
+
ttk.Combobox(screenshot_frame, textvariable=self.screenshot_extension_value, values=['webp', 'avif', 'png', 'jpeg'],
|
1394
|
+
state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1395
|
+
self.current_row += 1
|
1396
|
+
|
1397
|
+
ffmpeg_i18n = ss_i18n.get('ffmpeg_options', {})
|
1398
|
+
HoverInfoLabelWidget(screenshot_frame, text=ffmpeg_i18n.get('label', '...'),
|
1399
|
+
tooltip=ffmpeg_i18n.get('tooltip', '...'), foreground="red",
|
1400
|
+
font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1401
|
+
ttk.Entry(screenshot_frame, width=50, textvariable=self.screenshot_custom_ffmpeg_settings_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1402
|
+
self.current_row += 1
|
1403
|
+
|
1404
|
+
timing_i18n = ss_i18n.get('timing', {})
|
1405
|
+
HoverInfoLabelWidget(screenshot_frame, text=timing_i18n.get('label', '...'),
|
1406
|
+
tooltip=timing_i18n.get('tooltip', '...'),
|
1407
|
+
row=self.current_row, column=0)
|
1408
|
+
ttk.Combobox(screenshot_frame, textvariable=self.screenshot_timing_value, values=['beginning', 'middle', 'end'], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1409
|
+
self.current_row += 1
|
1410
|
+
|
1411
|
+
offset_i18n = ss_i18n.get('offset', {})
|
1412
|
+
HoverInfoLabelWidget(screenshot_frame, text=offset_i18n.get('label', '...'),
|
1413
|
+
tooltip=offset_i18n.get('tooltip', '...'),
|
1414
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1415
|
+
ttk.Entry(screenshot_frame, textvariable=self.seconds_after_line_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1416
|
+
self.current_row += 1
|
1417
|
+
|
1418
|
+
selector_i18n = ss_i18n.get('use_selector', {})
|
1419
|
+
HoverInfoLabelWidget(screenshot_frame, text=selector_i18n.get('label', '...'),
|
1420
|
+
tooltip=selector_i18n.get('tooltip', '...'),
|
1421
|
+
row=self.current_row, column=0)
|
1422
|
+
ttk.Checkbutton(screenshot_frame, variable=self.use_screenshot_selector_value, bootstyle="round-toggle").grid(
|
1423
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1424
|
+
self.current_row += 1
|
1425
|
+
|
1426
|
+
hotkey_i18n = ss_i18n.get('hotkey', {})
|
1427
|
+
HoverInfoLabelWidget(screenshot_frame, text=hotkey_i18n.get('label', '...'), tooltip=hotkey_i18n.get('tooltip', '...'),
|
1428
|
+
row=self.current_row, column=0)
|
1429
|
+
ttk.Entry(screenshot_frame, textvariable=self.take_screenshot_hotkey_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1430
|
+
self.current_row += 1
|
1431
|
+
|
1432
|
+
hotkey_update_i18n = ss_i18n.get('hotkey_updates_anki', {})
|
1433
|
+
HoverInfoLabelWidget(screenshot_frame, text=hotkey_update_i18n.get('label', '...'),
|
1434
|
+
tooltip=hotkey_update_i18n.get('tooltip', '...'),
|
1435
|
+
row=self.current_row, column=0)
|
1436
|
+
ttk.Checkbutton(screenshot_frame, variable=self.screenshot_hotkey_update_anki_value, bootstyle="round-toggle").grid(
|
1437
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1438
|
+
self.current_row += 1
|
1439
|
+
|
1440
|
+
self.add_reset_button(screenshot_frame, "screenshot", self.current_row, 0, self.create_screenshot_tab)
|
1441
|
+
|
1442
|
+
for col in range(3): screenshot_frame.grid_columnconfigure(col, weight=0)
|
1443
|
+
for row in range(self.current_row): screenshot_frame.grid_rowconfigure(row, minsize=30)
|
1444
|
+
|
1445
|
+
return screenshot_frame
|
1446
|
+
|
1447
|
+
def update_audio_ffmpeg_settings(self, event):
|
1448
|
+
selected_option = self.ffmpeg_audio_preset_options.get()
|
1449
|
+
if selected_option in self.ffmpeg_audio_preset_options_map:
|
1450
|
+
self.audio_ffmpeg_reencode_options_value.set(self.ffmpeg_audio_preset_options_map[selected_option])
|
1451
|
+
else:
|
1452
|
+
self.audio_ffmpeg_reencode_options_value.set("")
|
1453
|
+
|
1454
|
+
@new_tab
|
1455
|
+
def create_audio_tab(self):
|
1456
|
+
if self.audio_tab is None:
|
1457
|
+
audio_i18n = self.i18n.get('tabs', {}).get('audio', {})
|
1458
|
+
self.audio_tab = ttk.Frame(self.notebook, padding=15)
|
1459
|
+
self.notebook.add(self.audio_tab, text=audio_i18n.get('title', 'Audio'))
|
1460
|
+
else:
|
1461
|
+
for widget in self.audio_tab.winfo_children():
|
1462
|
+
widget.destroy()
|
1463
|
+
|
1464
|
+
audio_frame = self.audio_tab
|
1465
|
+
audio_i18n = self.i18n.get('tabs', {}).get('audio', {})
|
1466
|
+
|
1467
|
+
enabled_i18n = audio_i18n.get('enabled', {})
|
1468
|
+
HoverInfoLabelWidget(audio_frame, text=enabled_i18n.get('label', '...'), tooltip=enabled_i18n.get('tooltip', '...'),
|
1469
|
+
row=self.current_row, column=0)
|
1470
|
+
ttk.Checkbutton(audio_frame, variable=self.audio_enabled_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1471
|
+
column=1, sticky='W', pady=2)
|
1472
|
+
self.current_row += 1
|
1473
|
+
|
1474
|
+
ext_i18n = audio_i18n.get('extension', {})
|
1475
|
+
HoverInfoLabelWidget(audio_frame, text=ext_i18n.get('label', '...'), tooltip=ext_i18n.get('tooltip', '...'),
|
1476
|
+
row=self.current_row, column=0)
|
1477
|
+
ttk.Combobox(audio_frame, textvariable=self.audio_extension_value, values=['opus', 'mp3', 'ogg', 'aac', 'm4a'], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1478
|
+
self.current_row += 1
|
1479
|
+
|
1480
|
+
begin_offset_i18n = audio_i18n.get('beginning_offset', {})
|
1481
|
+
HoverInfoLabelWidget(audio_frame, text=begin_offset_i18n.get('label', '...'),
|
1482
|
+
tooltip=begin_offset_i18n.get('tooltip', '...'),
|
1483
|
+
foreground="dark orange", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1484
|
+
ttk.Entry(audio_frame, textvariable=self.beginning_offset_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1485
|
+
|
1486
|
+
ttk.Button(audio_frame, text=audio_i18n.get('find_offset_button', 'Find Offset (WIP)'), command=self.call_audio_offset_selector,
|
1487
|
+
bootstyle="info").grid(row=self.current_row, column=2, sticky='EW', pady=2, padx=5)
|
1488
|
+
self.current_row += 1
|
1489
|
+
|
1490
|
+
end_offset_i18n = audio_i18n.get('end_offset', {})
|
1491
|
+
HoverInfoLabelWidget(audio_frame, text=end_offset_i18n.get('label', '...'),
|
1492
|
+
tooltip=end_offset_i18n.get('tooltip', '...'),
|
1493
|
+
foreground="red", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1494
|
+
ttk.Entry(audio_frame, textvariable=self.pre_vad_audio_offset_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1495
|
+
self.current_row += 1
|
1496
|
+
|
1497
|
+
ffmpeg_preset_i18n = audio_i18n.get('ffmpeg_preset', {})
|
1498
|
+
HoverInfoLabelWidget(audio_frame, text=ffmpeg_preset_i18n.get('label', '...'),
|
1499
|
+
tooltip=ffmpeg_preset_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1500
|
+
|
1501
|
+
preset_options_i18n = ffmpeg_preset_i18n.get('options', {})
|
1502
|
+
self.ffmpeg_audio_preset_options_map = {
|
1503
|
+
preset_options_i18n.get('no_reencode', "No Re-encode"): "",
|
1504
|
+
preset_options_i18n.get('fade_in', "Simple Fade-in..."): "-c:a {encoder} -f {format} -af \"afade=t=in:d=0.10\"",
|
1505
|
+
preset_options_i18n.get('loudness_norm', "Simple loudness..."): "-c:a {encoder} -f {format} -af \"loudnorm=I=-23:TP=-2,afade=t=in:d=0.10\"",
|
1506
|
+
preset_options_i18n.get('downmix_norm', "Downmix to mono..."): "-c:a {encoder} -ac 1 -f {format} -af \"loudnorm=I=-23:TP=-2:dual_mono=true,afade=t=in:d=0.10\"",
|
1507
|
+
preset_options_i18n.get('downmix_norm_low_bitrate', "Downmix to mono, 30kbps..."): "-c:a {encoder} -b:a 30k -ac 1 -f {format} -af \"loudnorm=I=-23:TP=-2:dual_mono=true,afade=t=in:d=0.10\"",
|
1508
|
+
preset_options_i18n.get('custom', "Custom"): get_config().audio.custom_encode_settings,
|
1509
|
+
}
|
1510
|
+
|
1511
|
+
self.ffmpeg_audio_preset_options = ttk.Combobox(audio_frame,
|
1512
|
+
values=list(self.ffmpeg_audio_preset_options_map.keys()),
|
1513
|
+
width=50, state="readonly")
|
1514
|
+
self.ffmpeg_audio_preset_options.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1515
|
+
self.ffmpeg_audio_preset_options.bind("<<ComboboxSelected>>", self.update_audio_ffmpeg_settings)
|
1516
|
+
self.current_row += 1
|
1517
|
+
|
1518
|
+
ffmpeg_options_i18n = audio_i18n.get('ffmpeg_options', {})
|
1519
|
+
HoverInfoLabelWidget(audio_frame, text=ffmpeg_options_i18n.get('label', '...'),
|
1520
|
+
tooltip=ffmpeg_options_i18n.get('tooltip', '...'), foreground="red",
|
1521
|
+
font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1522
|
+
ttk.Entry(audio_frame, width=50, textvariable=self.audio_ffmpeg_reencode_options_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1523
|
+
self.current_row += 1
|
1524
|
+
|
1525
|
+
anki_media_i18n = audio_i18n.get('anki_media_collection', {})
|
1526
|
+
HoverInfoLabelWidget(audio_frame, text=anki_media_i18n.get('label', '...'),
|
1527
|
+
tooltip=anki_media_i18n.get('tooltip', '...'),
|
1528
|
+
foreground="green", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1529
|
+
self.anki_media_collection_entry = ttk.Entry(audio_frame, textvariable=self.anki_media_collection_value)
|
1530
|
+
self.anki_media_collection_entry.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1531
|
+
self.current_row += 1
|
1532
|
+
|
1533
|
+
ext_tool_i18n = audio_i18n.get('external_tool', {})
|
1534
|
+
HoverInfoLabelWidget(audio_frame, text=ext_tool_i18n.get('label', '...'),
|
1535
|
+
tooltip=ext_tool_i18n.get('tooltip', '...'),
|
1536
|
+
foreground="green", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1537
|
+
self.external_tool_entry = ttk.Entry(audio_frame, textvariable=self.external_tool_value)
|
1538
|
+
self.external_tool_entry.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1539
|
+
|
1540
|
+
ext_tool_enabled_i18n = audio_i18n.get('external_tool_enabled', {})
|
1541
|
+
HoverInfoLabelWidget(audio_frame, text=ext_tool_enabled_i18n.get('label', '...'), tooltip=ext_tool_enabled_i18n.get('tooltip', '...'),
|
1542
|
+
row=self.current_row, column=2, foreground="green", font=("Helvetica", 10, "bold"))
|
1543
|
+
ttk.Checkbutton(audio_frame, variable=self.external_tool_enabled_value, bootstyle="round-toggle").grid(
|
1544
|
+
row=self.current_row, column=3, sticky='W', padx=10, pady=5)
|
1545
|
+
self.current_row += 1
|
1546
|
+
|
1547
|
+
ttk.Button(audio_frame, text=audio_i18n.get('install_ocenaudio_button', 'Install Ocenaudio'), command=self.download_and_install_ocen,
|
1548
|
+
bootstyle="info").grid(row=self.current_row, column=0, pady=5)
|
1549
|
+
ttk.Button(audio_frame, text=audio_i18n.get('get_anki_media_button', 'Get Anki Media Collection'),
|
1550
|
+
command=self.set_default_anki_media_collection, bootstyle="info").grid(row=self.current_row,
|
1551
|
+
column=1, pady=5)
|
1552
|
+
self.current_row += 1
|
1553
|
+
|
1554
|
+
self.add_reset_button(audio_frame, "audio", self.current_row, 0, self.create_audio_tab)
|
1555
|
+
|
1556
|
+
for col in range(5): audio_frame.grid_columnconfigure(col, weight=0)
|
1557
|
+
for row in range(self.current_row): audio_frame.grid_rowconfigure(row, minsize=30)
|
1558
|
+
|
1559
|
+
return audio_frame
|
1560
|
+
|
1561
|
+
def call_audio_offset_selector(self):
|
1562
|
+
try:
|
1563
|
+
path, beginning_offset, end_offset = gsm_state.previous_trim_args
|
1564
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
1565
|
+
script_path = os.path.join(current_dir, "audio_offset_selector.py")
|
1566
|
+
|
1567
|
+
logger.info(' '.join([sys.executable, "-m", "GameSentenceMiner.util.audio_offset_selector",
|
1568
|
+
"--path", path, "--beginning_offset", str(beginning_offset), "--end_offset", str(end_offset)]))
|
1569
|
+
|
1570
|
+
result = subprocess.run(
|
1571
|
+
[sys.executable, "-m", "GameSentenceMiner.util.audio_offset_selector",
|
1572
|
+
"--path", path, "--beginning_offset", str(beginning_offset), "--end_offset", str(end_offset)],
|
1573
|
+
capture_output=True, text=True, check=False
|
1574
|
+
)
|
1575
|
+
if result.returncode != 0:
|
1576
|
+
logger.error(f"Script failed with return code: {result.returncode}")
|
1577
|
+
return None
|
1578
|
+
|
1579
|
+
logger.info(result)
|
1580
|
+
logger.info(f"Audio offset selector script output: {result.stdout.strip()}")
|
1581
|
+
pyperclip.copy(result.stdout.strip())
|
1582
|
+
|
1583
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('offset_copied', {})
|
1584
|
+
messagebox.showinfo(dialog_i18n.get('title', 'Clipboard'), dialog_i18n.get('message', 'Offset copied!'))
|
1585
|
+
return result.stdout.strip()
|
1586
|
+
|
1587
|
+
except subprocess.CalledProcessError as e:
|
1588
|
+
logger.error(f"Error calling script: {e}\nStderr: {e.stderr.strip()}")
|
1589
|
+
return None
|
1590
|
+
except FileNotFoundError:
|
1591
|
+
logger.error(f"Error: Script not found at {script_path}.")
|
1592
|
+
return None
|
1593
|
+
except Exception as e:
|
1594
|
+
logger.error(f"An unexpected error occurred: {e}")
|
1595
|
+
return None
|
1596
|
+
|
1597
|
+
@new_tab
|
1598
|
+
def create_obs_tab(self):
|
1599
|
+
if self.obs_tab is None:
|
1600
|
+
obs_i18n = self.i18n.get('tabs', {}).get('obs', {})
|
1601
|
+
self.obs_tab = ttk.Frame(self.notebook, padding=15)
|
1602
|
+
self.notebook.add(self.obs_tab, text=obs_i18n.get('title', 'OBS'))
|
1603
|
+
else:
|
1604
|
+
for widget in self.obs_tab.winfo_children():
|
1605
|
+
widget.destroy()
|
1606
|
+
|
1607
|
+
obs_frame = self.obs_tab
|
1608
|
+
obs_i18n = self.i18n.get('tabs', {}).get('obs', {})
|
1609
|
+
|
1610
|
+
enabled_i18n = obs_i18n.get('enabled', {})
|
1611
|
+
HoverInfoLabelWidget(obs_frame, text=enabled_i18n.get('label', '...'), tooltip=enabled_i18n.get('tooltip', '...'),
|
1612
|
+
row=self.current_row, column=0)
|
1613
|
+
ttk.Checkbutton(obs_frame, variable=self.obs_enabled_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1614
|
+
column=1, sticky='W', pady=2)
|
1615
|
+
self.current_row += 1
|
1616
|
+
|
1617
|
+
open_i18n = obs_i18n.get('open_obs', {})
|
1618
|
+
HoverInfoLabelWidget(obs_frame, text=open_i18n.get('label', '...'), tooltip=open_i18n.get('tooltip', '...'), row=self.current_row,
|
1619
|
+
column=0)
|
1620
|
+
ttk.Checkbutton(obs_frame, variable=self.obs_open_obs_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1621
|
+
column=1, sticky='W', pady=2)
|
1622
|
+
self.current_row += 1
|
1623
|
+
|
1624
|
+
close_i18n = obs_i18n.get('close_obs', {})
|
1625
|
+
HoverInfoLabelWidget(obs_frame, text=close_i18n.get('label', '...'), tooltip=close_i18n.get('tooltip', '...'),
|
1626
|
+
row=self.current_row, column=0)
|
1627
|
+
ttk.Checkbutton(obs_frame, variable=self.obs_close_obs_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1628
|
+
column=1, sticky='W', pady=2)
|
1629
|
+
self.current_row += 1
|
1630
|
+
|
1631
|
+
host_i18n = obs_i18n.get('host', {})
|
1632
|
+
HoverInfoLabelWidget(obs_frame, text=host_i18n.get('label', '...'), tooltip=host_i18n.get('tooltip', '...'),
|
1633
|
+
row=self.current_row, column=0)
|
1634
|
+
ttk.Entry(obs_frame, textvariable=self.obs_host_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1635
|
+
self.current_row += 1
|
1636
|
+
|
1637
|
+
port_i18n = obs_i18n.get('port', {})
|
1638
|
+
HoverInfoLabelWidget(obs_frame, text=port_i18n.get('label', '...'), tooltip=port_i18n.get('tooltip', '...'),
|
1639
|
+
row=self.current_row, column=0)
|
1640
|
+
ttk.Entry(obs_frame, textvariable=self.obs_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1641
|
+
self.current_row += 1
|
1642
|
+
|
1643
|
+
pass_i18n = obs_i18n.get('password', {})
|
1644
|
+
HoverInfoLabelWidget(obs_frame, text=pass_i18n.get('label', '...'), tooltip=pass_i18n.get('tooltip', '...'),
|
1645
|
+
row=self.current_row, column=0)
|
1646
|
+
ttk.Entry(obs_frame, show="*", textvariable=self.obs_password_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1647
|
+
self.current_row += 1
|
1648
|
+
|
1649
|
+
game_scene_i18n = obs_i18n.get('game_from_scene', {})
|
1650
|
+
HoverInfoLabelWidget(obs_frame, text=game_scene_i18n.get('label', '...'), tooltip=game_scene_i18n.get('tooltip', '...'),
|
1651
|
+
row=self.current_row, column=0)
|
1652
|
+
ttk.Checkbutton(obs_frame, variable=self.obs_get_game_from_scene_name_value, bootstyle="round-toggle").grid(
|
1653
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1654
|
+
self.current_row += 1
|
1655
|
+
|
1656
|
+
min_size_i18n = obs_i18n.get('min_replay_size', {})
|
1657
|
+
HoverInfoLabelWidget(obs_frame, text=min_size_i18n.get('label', '...'),
|
1658
|
+
tooltip=min_size_i18n.get('tooltip', '...'),
|
1659
|
+
row=self.current_row, column=0)
|
1660
|
+
ttk.Entry(obs_frame, textvariable=self.obs_minimum_replay_size_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1661
|
+
self.current_row += 1
|
1662
|
+
|
1663
|
+
self.add_reset_button(obs_frame, "obs", self.current_row, 0, self.create_obs_tab)
|
1664
|
+
|
1665
|
+
for col in range(3): obs_frame.grid_columnconfigure(col, weight=0)
|
1666
|
+
for row in range(self.current_row): obs_frame.grid_rowconfigure(row, minsize=30)
|
1667
|
+
|
1668
|
+
return obs_frame
|
1669
|
+
|
1670
|
+
@new_tab
|
1671
|
+
def create_profiles_tab(self):
|
1672
|
+
if self.profiles_tab is None:
|
1673
|
+
profiles_i18n = self.i18n.get('tabs', {}).get('profiles', {})
|
1674
|
+
self.profiles_tab = ttk.Frame(self.notebook, padding=15)
|
1675
|
+
self.notebook.add(self.profiles_tab, text=profiles_i18n.get('title', 'Profiles'))
|
1676
|
+
else:
|
1677
|
+
for widget in self.profiles_tab.winfo_children():
|
1678
|
+
widget.destroy()
|
1679
|
+
|
1680
|
+
profiles_frame = self.profiles_tab
|
1681
|
+
profiles_i18n = self.i18n.get('tabs', {}).get('profiles', {})
|
1682
|
+
|
1683
|
+
select_i18n = profiles_i18n.get('select_profile', {})
|
1684
|
+
HoverInfoLabelWidget(profiles_frame, text=select_i18n.get('label', '...'), tooltip=select_i18n.get('tooltip', '...'),
|
1685
|
+
row=self.current_row, column=0)
|
1686
|
+
self.profile_var = tk.StringVar(value=self.settings.name)
|
1687
|
+
self.profile_combobox = ttk.Combobox(profiles_frame, textvariable=self.profile_var,
|
1688
|
+
values=list(self.master_config.configs.keys()), state="readonly")
|
1689
|
+
self.profile_combobox.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1690
|
+
self.profile_combobox.bind("<<ComboboxSelected>>", self.on_profile_change)
|
1691
|
+
self.current_row += 1
|
1692
|
+
|
1693
|
+
button_row = self.current_row
|
1694
|
+
ttk.Button(profiles_frame, text=profiles_i18n.get('add_button', 'Add Profile'), command=self.add_profile, bootstyle="primary").grid(
|
1695
|
+
row=button_row, column=0, pady=5)
|
1696
|
+
ttk.Button(profiles_frame, text=profiles_i18n.get('copy_button', 'Copy Profile'), command=self.copy_profile, bootstyle="secondary").grid(
|
1697
|
+
row=button_row, column=1, pady=5)
|
1698
|
+
self.delete_profile_button = ttk.Button(profiles_frame, text=profiles_i18n.get('delete_button', 'Delete Config'), command=self.delete_profile,
|
1699
|
+
bootstyle="danger")
|
1700
|
+
if self.master_config.current_profile != DEFAULT_CONFIG:
|
1701
|
+
self.delete_profile_button.grid(row=button_row, column=2, pady=5)
|
1702
|
+
else:
|
1703
|
+
self.delete_profile_button.grid_remove()
|
1704
|
+
self.current_row += 1
|
1705
|
+
|
1706
|
+
scene_i18n = profiles_i18n.get('obs_scene', {})
|
1707
|
+
HoverInfoLabelWidget(profiles_frame, text=scene_i18n.get('label', '...'),
|
1708
|
+
tooltip=scene_i18n.get('tooltip', '...'),
|
1709
|
+
row=self.current_row, column=0)
|
1710
|
+
self.obs_scene_var = tk.StringVar(value="")
|
1711
|
+
self.obs_scene_listbox = tk.Listbox(profiles_frame, listvariable=self.obs_scene_var, selectmode=tk.MULTIPLE,
|
1712
|
+
height=10, width=50, selectbackground=ttk.Style().colors.primary)
|
1713
|
+
self.obs_scene_listbox.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1714
|
+
self.obs_scene_listbox.bind("<<ListboxSelect>>", self.on_obs_scene_select)
|
1715
|
+
ttk.Button(profiles_frame, text=profiles_i18n.get('refresh_scenes_button', 'Refresh Scenes'), command=self.refresh_obs_scenes, bootstyle="outline").grid(
|
1716
|
+
row=self.current_row, column=2, pady=5)
|
1717
|
+
self.current_row += 1
|
1718
|
+
|
1719
|
+
switch_i18n = profiles_i18n.get('switch_to_default', {})
|
1720
|
+
HoverInfoLabelWidget(profiles_frame, text=switch_i18n.get('label', '...'),
|
1721
|
+
tooltip=switch_i18n.get('tooltip', '...'),
|
1722
|
+
row=self.current_row, column=0)
|
1723
|
+
ttk.Checkbutton(profiles_frame, variable=self.switch_to_default_if_not_found_value, bootstyle="round-toggle").grid(
|
1724
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1725
|
+
self.current_row += 1
|
1726
|
+
|
1727
|
+
for col in range(4): profiles_frame.grid_columnconfigure(col, weight=0)
|
1728
|
+
for row in range(self.current_row): profiles_frame.grid_rowconfigure(row, minsize=30)
|
1729
|
+
|
1730
|
+
return profiles_frame
|
1731
|
+
|
1732
|
+
def on_obs_scene_select(self, event):
|
1733
|
+
self.settings.scenes = [self.obs_scene_listbox.get(i) for i in
|
1734
|
+
self.obs_scene_listbox.curselection()]
|
1735
|
+
self.obs_scene_listbox_changed = True
|
1736
|
+
|
1737
|
+
def refresh_obs_scenes(self):
|
1738
|
+
scenes = obs.get_obs_scenes()
|
1739
|
+
obs_scene_names = [scene['sceneName'] for scene in scenes]
|
1740
|
+
self.obs_scene_listbox.delete(0, tk.END)
|
1741
|
+
for scene_name in obs_scene_names:
|
1742
|
+
self.obs_scene_listbox.insert(tk.END, scene_name)
|
1743
|
+
for i, scene in enumerate(obs_scene_names):
|
1744
|
+
if scene.strip() in self.settings.scenes:
|
1745
|
+
self.obs_scene_listbox.select_set(i)
|
1746
|
+
self.obs_scene_listbox.activate(i)
|
1747
|
+
self.obs_scene_listbox.update_idletasks()
|
1748
|
+
|
1749
|
+
@new_tab
|
1750
|
+
def create_advanced_tab(self):
|
1751
|
+
if self.advanced_tab is None:
|
1752
|
+
advanced_i18n = self.i18n.get('tabs', {}).get('advanced', {})
|
1753
|
+
self.advanced_tab = ttk.Frame(self.notebook, padding=15)
|
1754
|
+
self.notebook.add(self.advanced_tab, text=advanced_i18n.get('title', 'Advanced'))
|
1755
|
+
else:
|
1756
|
+
for widget in self.advanced_tab.winfo_children():
|
1757
|
+
widget.destroy()
|
1758
|
+
|
1759
|
+
advanced_frame = self.advanced_tab
|
1760
|
+
advanced_i18n = self.i18n.get('tabs', {}).get('advanced', {})
|
1761
|
+
browse_text = self.i18n.get('buttons', {}).get('browse', 'Browse')
|
1762
|
+
|
1763
|
+
ttk.Label(advanced_frame, text=advanced_i18n.get('player_note', '...'),
|
1764
|
+
foreground="red", font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=3,
|
1765
|
+
sticky='W', pady=5)
|
1766
|
+
self.current_row += 1
|
1767
|
+
|
1768
|
+
audio_player_i18n = advanced_i18n.get('audio_player_path', {})
|
1769
|
+
HoverInfoLabelWidget(advanced_frame, text=audio_player_i18n.get('label', '...'),
|
1770
|
+
tooltip=audio_player_i18n.get('tooltip', '...'),
|
1771
|
+
row=self.current_row, column=0)
|
1772
|
+
audio_player_entry = ttk.Entry(advanced_frame, width=50, textvariable=self.audio_player_path_value)
|
1773
|
+
audio_player_entry.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1774
|
+
ttk.Button(advanced_frame, text=browse_text, command=lambda: self.browse_file(audio_player_entry),
|
1775
|
+
bootstyle="outline").grid(row=self.current_row, column=2, padx=5, pady=2)
|
1776
|
+
self.current_row += 1
|
1777
|
+
|
1778
|
+
video_player_i18n = advanced_i18n.get('video_player_path', {})
|
1779
|
+
HoverInfoLabelWidget(advanced_frame, text=video_player_i18n.get('label', '...'),
|
1780
|
+
tooltip=video_player_i18n.get('tooltip', '...'),
|
1781
|
+
row=self.current_row, column=0)
|
1782
|
+
video_player_entry = ttk.Entry(advanced_frame, width=50, textvariable=self.video_player_path_value)
|
1783
|
+
video_player_entry.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1784
|
+
ttk.Button(advanced_frame, text=browse_text, command=lambda: self.browse_file(video_player_entry),
|
1785
|
+
bootstyle="outline").grid(row=self.current_row, column=2, padx=5, pady=2)
|
1786
|
+
self.current_row += 1
|
1787
|
+
|
1788
|
+
play_hotkey_i18n = advanced_i18n.get('play_latest_hotkey', {})
|
1789
|
+
HoverInfoLabelWidget(advanced_frame, text=play_hotkey_i18n.get('label', '...'),
|
1790
|
+
tooltip=play_hotkey_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1791
|
+
ttk.Entry(advanced_frame, textvariable=self.play_latest_audio_hotkey_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1792
|
+
self.current_row += 1
|
1793
|
+
|
1794
|
+
linebreak_i18n = advanced_i18n.get('multiline_linebreak', {})
|
1795
|
+
HoverInfoLabelWidget(advanced_frame, text=linebreak_i18n.get('label', '...'),
|
1796
|
+
tooltip=linebreak_i18n.get('tooltip', '...'),
|
1797
|
+
row=self.current_row, column=0)
|
1798
|
+
ttk.Entry(advanced_frame, textvariable=self.multi_line_line_break_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1799
|
+
self.current_row += 1
|
1800
|
+
|
1801
|
+
storage_field_i18n = advanced_i18n.get('multiline_storage_field', {})
|
1802
|
+
HoverInfoLabelWidget(advanced_frame, text=storage_field_i18n.get('label', '...'),
|
1803
|
+
tooltip=storage_field_i18n.get('tooltip', '...'),
|
1804
|
+
row=self.current_row, column=0)
|
1805
|
+
ttk.Entry(advanced_frame, textvariable=self.multi_line_sentence_storage_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1806
|
+
self.current_row += 1
|
1807
|
+
|
1808
|
+
ocr_port_i18n = advanced_i18n.get('ocr_port', {})
|
1809
|
+
HoverInfoLabelWidget(advanced_frame, text=ocr_port_i18n.get('label', '...'),
|
1810
|
+
tooltip=ocr_port_i18n.get('tooltip', '...'),
|
1811
|
+
row=self.current_row, column=0)
|
1812
|
+
ttk.Entry(advanced_frame, textvariable=self.ocr_websocket_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1813
|
+
self.current_row += 1
|
1814
|
+
|
1815
|
+
comm_port_i18n = advanced_i18n.get('texthooker_comm_port', {})
|
1816
|
+
HoverInfoLabelWidget(advanced_frame, text=comm_port_i18n.get('label', '...'),
|
1817
|
+
tooltip=comm_port_i18n.get('tooltip', '...'),
|
1818
|
+
row=self.current_row, column=0)
|
1819
|
+
ttk.Entry(advanced_frame, textvariable=self.texthooker_communication_websocket_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1820
|
+
self.current_row += 1
|
1821
|
+
|
1822
|
+
export_port_i18n = advanced_i18n.get('plaintext_export_port', {})
|
1823
|
+
HoverInfoLabelWidget(advanced_frame, text=export_port_i18n.get('label', '...'),
|
1824
|
+
tooltip=export_port_i18n.get('tooltip', '...'),
|
1825
|
+
row=self.current_row, column=0)
|
1826
|
+
ttk.Entry(advanced_frame, textvariable=self.plaintext_websocket_export_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1827
|
+
self.current_row += 1
|
1828
|
+
|
1829
|
+
reset_hotkey_i18n = advanced_i18n.get('reset_line_hotkey', {})
|
1830
|
+
HoverInfoLabelWidget(advanced_frame, text=reset_hotkey_i18n.get('label', '...'),
|
1831
|
+
tooltip=reset_hotkey_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1832
|
+
ttk.Entry(advanced_frame, textvariable=self.reset_line_hotkey_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1833
|
+
self.current_row += 1
|
1834
|
+
|
1835
|
+
polling_i18n = advanced_i18n.get('polling_rate', {})
|
1836
|
+
HoverInfoLabelWidget(advanced_frame, text=polling_i18n.get('label', '...'),
|
1837
|
+
tooltip=polling_i18n.get('tooltip', '...'),
|
1838
|
+
row=self.current_row, column=0)
|
1839
|
+
ttk.Entry(advanced_frame, textvariable=self.polling_rate_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1840
|
+
self.current_row += 1
|
1841
|
+
|
1842
|
+
current_ver_i18n = advanced_i18n.get('current_version', {})
|
1843
|
+
HoverInfoLabelWidget(advanced_frame, text=current_ver_i18n.get('label', 'Current Version:'), bootstyle="secondary",
|
1844
|
+
tooltip=current_ver_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1845
|
+
self.current_version = ttk.Label(advanced_frame, text=get_current_version(), bootstyle="secondary")
|
1846
|
+
self.current_version.grid(row=self.current_row, column=1, sticky='W', pady=2)
|
1847
|
+
self.current_row += 1
|
1848
|
+
|
1849
|
+
latest_ver_i18n = advanced_i18n.get('latest_version', {})
|
1850
|
+
HoverInfoLabelWidget(advanced_frame, text=latest_ver_i18n.get('label', 'Latest Version:'), bootstyle="secondary",
|
1851
|
+
tooltip=latest_ver_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1852
|
+
self.latest_version = ttk.Label(advanced_frame, text=get_latest_version(), bootstyle="secondary")
|
1853
|
+
self.latest_version.grid(row=self.current_row, column=1, sticky='W', pady=2)
|
1854
|
+
self.current_row += 1
|
1855
|
+
|
1856
|
+
self.add_reset_button(advanced_frame, "advanced", self.current_row, 0, self.create_advanced_tab)
|
1857
|
+
|
1858
|
+
for col in range(4): advanced_frame.grid_columnconfigure(col, weight=0)
|
1859
|
+
for row in range(self.current_row): advanced_frame.grid_rowconfigure(row, minsize=30)
|
1860
|
+
|
1861
|
+
return advanced_frame
|
1862
|
+
|
1863
|
+
@new_tab
|
1864
|
+
def create_ai_tab(self):
|
1865
|
+
if self.ai_tab is None:
|
1866
|
+
ai_i18n = self.i18n.get('tabs', {}).get('ai', {})
|
1867
|
+
self.ai_tab = ttk.Frame(self.notebook, padding=15)
|
1868
|
+
self.notebook.add(self.ai_tab, text=ai_i18n.get('title', 'AI'))
|
1869
|
+
else:
|
1870
|
+
for widget in self.ai_tab.winfo_children():
|
1871
|
+
widget.destroy()
|
1872
|
+
|
1873
|
+
ai_frame = self.ai_tab
|
1874
|
+
ai_i18n = self.i18n.get('tabs', {}).get('ai', {})
|
1875
|
+
|
1876
|
+
enabled_i18n = ai_i18n.get('enabled', {})
|
1877
|
+
HoverInfoLabelWidget(ai_frame, text=enabled_i18n.get('label', '...'), tooltip=enabled_i18n.get('tooltip', '...'),
|
1878
|
+
row=self.current_row, column=0)
|
1879
|
+
ttk.Checkbutton(ai_frame, variable=self.ai_enabled_value, bootstyle="round-toggle").grid(row=self.current_row,
|
1880
|
+
column=1, sticky='W', pady=2)
|
1881
|
+
self.current_row += 1
|
1882
|
+
|
1883
|
+
provider_i18n = ai_i18n.get('provider', {})
|
1884
|
+
HoverInfoLabelWidget(ai_frame, text=provider_i18n.get('label', '...'), tooltip=provider_i18n.get('tooltip', '...'), row=self.current_row,
|
1885
|
+
column=0)
|
1886
|
+
ttk.Combobox(ai_frame, textvariable=self.ai_provider_value, values=[AI_GEMINI, AI_GROQ, AI_LOCAL], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1887
|
+
self.current_row += 1
|
1888
|
+
|
1889
|
+
gemini_model_i18n = ai_i18n.get('gemini_model', {})
|
1890
|
+
HoverInfoLabelWidget(ai_frame, text=gemini_model_i18n.get('label', '...'), tooltip=gemini_model_i18n.get('tooltip', '...'),
|
1891
|
+
row=self.current_row, column=0)
|
1892
|
+
ttk.Combobox(ai_frame, textvariable=self.gemini_model_value, values=['gemma-3n-e4b-it', 'gemini-2.5-flash-lite', 'gemini-2.5-flash','gemini-2.0-flash', 'gemini-2.0-flash-lite'], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1893
|
+
self.current_row += 1
|
1894
|
+
|
1895
|
+
gemini_key_i18n = ai_i18n.get('gemini_api_key', {})
|
1896
|
+
HoverInfoLabelWidget(ai_frame, text=gemini_key_i18n.get('label', '...'),
|
1897
|
+
tooltip=gemini_key_i18n.get('tooltip', '...'),
|
1898
|
+
foreground="green", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1899
|
+
ttk.Entry(ai_frame, show="*", textvariable=self.gemini_api_key_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1900
|
+
self.current_row += 1
|
1901
|
+
|
1902
|
+
groq_model_i18n = ai_i18n.get('groq_model', {})
|
1903
|
+
HoverInfoLabelWidget(ai_frame, text=groq_model_i18n.get('label', '...'), tooltip=groq_model_i18n.get('tooltip', '...'),
|
1904
|
+
row=self.current_row, column=0)
|
1905
|
+
ttk.Combobox(ai_frame, textvariable=self.groq_model_value, values=['meta-llama/llama-4-maverick-17b-128e-instruct',
|
1906
|
+
'meta-llama/llama-4-scout-17b-16e-instruct',
|
1907
|
+
'llama-3.1-8b-instant'], state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1908
|
+
self.current_row += 1
|
1909
|
+
|
1910
|
+
groq_key_i18n = ai_i18n.get('groq_api_key', {})
|
1911
|
+
HoverInfoLabelWidget(ai_frame, text=groq_key_i18n.get('label', '...'), tooltip=groq_key_i18n.get('tooltip', '...'),
|
1912
|
+
row=self.current_row, column=0)
|
1913
|
+
ttk.Entry(ai_frame, show="*", textvariable=self.groq_api_key_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1914
|
+
self.current_row += 1
|
1915
|
+
|
1916
|
+
local_model_i18n = ai_i18n.get('local_model', {})
|
1917
|
+
HoverInfoLabelWidget(ai_frame, text=local_model_i18n.get('label', '...'), tooltip=local_model_i18n.get('tooltip', '...'),
|
1918
|
+
foreground="red", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1919
|
+
ttk.Combobox(ai_frame, textvariable=self.local_ai_model_value, values=[OFF, 'facebook/nllb-200-distilled-600M', 'facebook/nllb-200-1.3B', 'facebook/nllb-200-3.3B']).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1920
|
+
self.current_row += 1
|
1921
|
+
|
1922
|
+
anki_field_i18n = ai_i18n.get('anki_field', {})
|
1923
|
+
HoverInfoLabelWidget(ai_frame, text=anki_field_i18n.get('label', '...'), tooltip=anki_field_i18n.get('tooltip', '...'),
|
1924
|
+
row=self.current_row, column=0)
|
1925
|
+
ttk.Entry(ai_frame, textvariable=self.ai_anki_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1926
|
+
self.current_row += 1
|
1927
|
+
|
1928
|
+
context_i18n = ai_i18n.get('context_length', {})
|
1929
|
+
HoverInfoLabelWidget(ai_frame, text=context_i18n.get('label', '...'), tooltip=context_i18n.get('tooltip', '...'),
|
1930
|
+
foreground="red", font=("Helvetica", 10, "bold"), row=self.current_row, column=0)
|
1931
|
+
ttk.Entry(ai_frame, textvariable=self.ai_dialogue_context_length_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1932
|
+
self.current_row += 1
|
1933
|
+
|
1934
|
+
canned_trans_i18n = ai_i18n.get('use_canned_translation', {})
|
1935
|
+
HoverInfoLabelWidget(ai_frame, text=canned_trans_i18n.get('label', '...'),
|
1936
|
+
tooltip=canned_trans_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1937
|
+
ttk.Checkbutton(ai_frame, variable=self.use_canned_translation_prompt_value, bootstyle="round-toggle").grid(
|
1938
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1939
|
+
self.current_row += 1
|
1940
|
+
|
1941
|
+
canned_context_i18n = ai_i18n.get('use_canned_context', {})
|
1942
|
+
HoverInfoLabelWidget(ai_frame, text=canned_context_i18n.get('label', '...'),
|
1943
|
+
tooltip=canned_context_i18n.get('tooltip', '...'), row=self.current_row, column=0)
|
1944
|
+
ttk.Checkbutton(ai_frame, variable=self.use_canned_context_prompt_value, bootstyle="round-toggle").grid(
|
1945
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1946
|
+
self.current_row += 1
|
1947
|
+
|
1948
|
+
custom_prompt_i18n = ai_i18n.get('custom_prompt', {})
|
1949
|
+
HoverInfoLabelWidget(ai_frame, text=custom_prompt_i18n.get('label', '...'), tooltip=custom_prompt_i18n.get('tooltip', '...'),
|
1950
|
+
row=self.current_row, column=0)
|
1951
|
+
self.custom_prompt = scrolledtext.ScrolledText(ai_frame, width=50, height=5, font=("TkDefaultFont", 9),
|
1952
|
+
relief="solid", borderwidth=1,
|
1953
|
+
highlightbackground=ttk.Style().colors.border)
|
1954
|
+
self.custom_prompt.insert(tk.END, self.settings.ai.custom_prompt)
|
1955
|
+
self.custom_prompt.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1956
|
+
self.current_row += 1
|
1957
|
+
|
1958
|
+
self.add_reset_button(ai_frame, "ai", self.current_row, 0, self.create_ai_tab)
|
1959
|
+
|
1960
|
+
for col in range(3): ai_frame.grid_columnconfigure(col, weight=0)
|
1961
|
+
for row in range(self.current_row): ai_frame.grid_rowconfigure(row, minsize=30)
|
1962
|
+
|
1963
|
+
return ai_frame
|
1964
|
+
|
1965
|
+
@new_tab
|
1966
|
+
def create_wip_tab(self):
|
1967
|
+
if self.wip_tab is None:
|
1968
|
+
wip_i18n = self.i18n.get('tabs', {}).get('wip', {})
|
1969
|
+
self.wip_tab = ttk.Frame(self.notebook, padding=15)
|
1970
|
+
self.notebook.add(self.wip_tab, text=wip_i18n.get('title', 'WIP'))
|
1971
|
+
else:
|
1972
|
+
for widget in self.wip_tab.winfo_children():
|
1973
|
+
widget.destroy()
|
1974
|
+
|
1975
|
+
wip_frame = self.wip_tab
|
1976
|
+
wip_i18n = self.i18n.get('tabs', {}).get('wip', {})
|
1977
|
+
try:
|
1978
|
+
ttk.Label(wip_frame, text=wip_i18n.get('warning_experimental', '...'),
|
1979
|
+
foreground="red", font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2,
|
1980
|
+
sticky='W', pady=5)
|
1981
|
+
self.current_row += 1
|
1982
|
+
|
1983
|
+
ttk.Label(wip_frame, text=wip_i18n.get('warning_overlay_deps', '...'),
|
1984
|
+
foreground="red", font=("Helvetica", 10, "bold")).grid(row=self.current_row, column=0, columnspan=2,
|
1985
|
+
sticky='W', pady=5)
|
1986
|
+
self.current_row += 1
|
1987
|
+
|
1988
|
+
overlay_port_i18n = wip_i18n.get('overlay_port', {})
|
1989
|
+
HoverInfoLabelWidget(wip_frame, text=overlay_port_i18n.get('label', '...'),
|
1990
|
+
tooltip=overlay_port_i18n.get('tooltip', '...'),
|
1991
|
+
row=self.current_row, column=0)
|
1992
|
+
ttk.Entry(wip_frame, textvariable=self.overlay_websocket_port_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1993
|
+
self.current_row += 1
|
1994
|
+
|
1995
|
+
overlay_send_i18n = wip_i18n.get('overlay_send', {})
|
1996
|
+
HoverInfoLabelWidget(wip_frame, text=overlay_send_i18n.get('label', '...'),
|
1997
|
+
tooltip=overlay_send_i18n.get('tooltip', '...'),
|
1998
|
+
row=self.current_row, column=0)
|
1999
|
+
ttk.Checkbutton(wip_frame, variable=self.overlay_websocket_send_value, bootstyle="round-toggle").grid(
|
2000
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
2001
|
+
self.current_row += 1
|
2002
|
+
|
2003
|
+
monitor_i18n = wip_i18n.get('monitor_capture', {})
|
2004
|
+
HoverInfoLabelWidget(wip_frame, text=monitor_i18n.get('label', '...'),
|
2005
|
+
tooltip=monitor_i18n.get('tooltip', '...'),
|
2006
|
+
row=self.current_row, column=0)
|
2007
|
+
self.monitor_to_capture = ttk.Combobox(wip_frame, values=self.monitors, state="readonly")
|
2008
|
+
|
2009
|
+
if self.monitors:
|
2010
|
+
# Ensure the index is valid
|
2011
|
+
monitor_index = self.settings.wip.monitor_to_capture
|
2012
|
+
if 0 <= monitor_index < len(self.monitors):
|
2013
|
+
self.monitor_to_capture.current(monitor_index)
|
2014
|
+
else:
|
2015
|
+
self.monitor_to_capture.current(0)
|
2016
|
+
else:
|
2017
|
+
self.monitor_to_capture.set(monitor_i18n.get('not_detected', "OwOCR Not Detected"))
|
2018
|
+
self.monitor_to_capture.grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
2019
|
+
self.current_row += 1
|
2020
|
+
|
2021
|
+
except Exception as e:
|
2022
|
+
logger.error(f"Error setting up wip tab to capture: {e}")
|
2023
|
+
ttk.Label(wip_frame, text=wip_i18n.get('error_setup', 'Error setting up WIP tab'), foreground="red").grid(row=self.current_row, column=0, columnspan=2, sticky='W', pady=5)
|
2024
|
+
|
2025
|
+
self.add_reset_button(wip_frame, "wip", self.current_row, 0, self.create_wip_tab)
|
2026
|
+
|
2027
|
+
for col in range(2): wip_frame.grid_columnconfigure(col, weight=0)
|
2028
|
+
for row in range(self.current_row): wip_frame.grid_rowconfigure(row, minsize=30)
|
2029
|
+
|
2030
|
+
return wip_frame
|
2031
|
+
|
2032
|
+
def on_profile_change(self, event):
|
2033
|
+
self.save_settings(profile_change=True)
|
2034
|
+
self.reload_settings(force_refresh=True)
|
2035
|
+
self.refresh_obs_scenes()
|
2036
|
+
if self.master_config.current_profile != DEFAULT_CONFIG:
|
2037
|
+
self.delete_profile_button.grid(row=1, column=2, pady=5)
|
2038
|
+
else:
|
2039
|
+
self.delete_profile_button.grid_remove()
|
2040
|
+
|
2041
|
+
def add_profile(self):
|
2042
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('add_profile', {})
|
2043
|
+
new_profile_name = simpledialog.askstring(dialog_i18n.get('title', 'Input'), dialog_i18n.get('prompt', 'Enter new profile name:'))
|
2044
|
+
if new_profile_name:
|
2045
|
+
self.master_config.configs[new_profile_name] = self.master_config.get_default_config()
|
2046
|
+
self.profile_combobox['values'] = list(self.master_config.configs.keys())
|
2047
|
+
self.profile_combobox.set(new_profile_name)
|
2048
|
+
self.save_settings()
|
2049
|
+
self.reload_settings()
|
2050
|
+
|
2051
|
+
def copy_profile(self):
|
2052
|
+
source_profile = self.profile_combobox.get()
|
2053
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('copy_profile', {})
|
2054
|
+
new_profile_name = simpledialog.askstring(dialog_i18n.get('title', 'Input'), dialog_i18n.get('prompt', 'Enter new profile name:'), parent=self.window)
|
2055
|
+
if new_profile_name and source_profile in self.master_config.configs:
|
2056
|
+
import copy
|
2057
|
+
self.master_config.configs[new_profile_name] = copy.deepcopy(self.master_config.configs[source_profile])
|
2058
|
+
self.master_config.configs[new_profile_name].name = new_profile_name
|
2059
|
+
self.profile_combobox['values'] = list(self.master_config.configs.keys())
|
2060
|
+
self.profile_combobox.set(new_profile_name)
|
2061
|
+
self.save_settings()
|
2062
|
+
self.reload_settings()
|
2063
|
+
|
2064
|
+
def delete_profile(self):
|
2065
|
+
profile_to_delete = self.profile_combobox.get()
|
2066
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('delete_profile', {})
|
2067
|
+
error_title = dialog_i18n.get('error_title', 'Error')
|
2068
|
+
|
2069
|
+
if profile_to_delete == "Default":
|
2070
|
+
messagebox.showerror(error_title, dialog_i18n.get('error_cannot_delete_default', 'Cannot delete the Default profile.'))
|
2071
|
+
return
|
2072
|
+
|
2073
|
+
if profile_to_delete and profile_to_delete in self.master_config.configs:
|
2074
|
+
confirm = messagebox.askyesno(dialog_i18n.get('title', 'Confirm Delete'),
|
2075
|
+
dialog_i18n.get('message', "Are you sure... '{profile_name}'?").format(profile_name=profile_to_delete),
|
2076
|
+
parent=self.window, icon='warning')
|
2077
|
+
if confirm:
|
2078
|
+
del self.master_config.configs[profile_to_delete]
|
2079
|
+
self.profile_combobox['values'] = list(self.master_config.configs.keys())
|
2080
|
+
self.profile_combobox.set("Default")
|
2081
|
+
self.master_config.current_profile = "Default"
|
2082
|
+
save_full_config(self.master_config)
|
2083
|
+
self.reload_settings()
|
2084
|
+
|
2085
|
+
def download_and_install_ocen(self):
|
2086
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('install_ocenaudio', {})
|
2087
|
+
confirm = messagebox.askyesno(dialog_i18n.get('title', 'Download OcenAudio?'),
|
2088
|
+
dialog_i18n.get('message', 'Would you like to download...?'),
|
2089
|
+
parent=self.window, icon='question')
|
2090
|
+
if confirm:
|
2091
|
+
self.external_tool_value.set(dialog_i18n.get('downloading_message', 'Downloading...'))
|
2092
|
+
exe_path = download_ocenaudio_if_needed()
|
2093
|
+
messagebox.showinfo(dialog_i18n.get('success_title', 'Download Complete'),
|
2094
|
+
dialog_i18n.get('success_message', 'Downloaded to {path}').format(path=exe_path),
|
2095
|
+
parent=self.window)
|
2096
|
+
self.external_tool_value.set(exe_path)
|
2097
|
+
self.save_settings()
|
2098
|
+
|
2099
|
+
def set_default_anki_media_collection(self):
|
2100
|
+
dialog_i18n = self.i18n.get('dialogs', {}).get('set_anki_media', {})
|
2101
|
+
confirm = messagebox.askyesno(dialog_i18n.get('title', 'Set Default Path?'),
|
2102
|
+
dialog_i18n.get('message', 'Would you like to set...?'),
|
2103
|
+
parent=self.window, icon='question')
|
2104
|
+
if confirm:
|
2105
|
+
default_path = get_default_anki_media_collection_path()
|
2106
|
+
if default_path != self.anki_media_collection_value.get():
|
2107
|
+
self.anki_media_collection_value.set(default_path)
|
2108
|
+
self.save_settings()
|
2109
|
+
|
2110
|
+
|
2111
|
+
if __name__ == '__main__':
|
2112
|
+
# Ensure 'en_us.json' is in the same directory as this script to run this example
|
2113
|
+
root = ttk.Window(themename='darkly')
|
2114
|
+
window = ConfigApp(root)
|
2115
|
+
window.show()
|
2116
|
+
window.window.mainloop()
|