GameSentenceMiner 2.14.15__tar.gz → 2.14.17__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.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ai/ai_prompting.py +1 -1
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/anki.py +107 -60
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/config_gui.py +25 -7
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/gsm.py +2 -1
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/en_us.json +8 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/ja_jp.json +8 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/zh_cn.json +8 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/obs.py +72 -10
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/configuration.py +8 -2
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/ffmpeg.py +153 -0
- gamesentenceminer-2.14.17/GameSentenceMiner/web/templates/index.html +50 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/PKG-INFO +1 -1
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/pyproject.toml +1 -1
- gamesentenceminer-2.14.15/GameSentenceMiner/web/templates/index.html +0 -50
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/gametext.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/owocr_helper.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/ocr.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/run.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/tools/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/tools/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/tools/ss_selector.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/tools/window_transparency.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/db.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/electron_config.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/get_overlay_coords.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/win10toast/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/win10toast/__main__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/vad.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/wip/__init___.py +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/LICENSE +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/README.md +0 -0
- {gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/setup.cfg +0 -0
{gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/ai/ai_prompting.py
RENAMED
@@ -29,7 +29,7 @@ Translate ONLY the provided line of game dialogue specified below into natural-s
|
|
29
29
|
**Output Requirements:**
|
30
30
|
- Provide only the single, best {get_config().general.get_native_language_name()} translation.
|
31
31
|
- Use expletives if they are natural for the context and enhance the translation's impact, but do not over-exaggerate.
|
32
|
-
- Carryover all HTML tags present in the original text to HTML tags surrounding their corresponding words in the translation. DO NOT CONVERT TO MARKDOWN.
|
32
|
+
- Carryover all HTML tags present in the original text to HTML tags surrounding their corresponding translated words in the translation. Look for the equivalent word, not the equivalent location. DO NOT CONVERT TO MARKDOWN.
|
33
33
|
- If there are no HTML tags present in the original text, do not add any in the translation whatsoever.
|
34
34
|
- Do not include notes, alternatives, explanations, or any other surrounding text. Absolutely nothing but the translated line.
|
35
35
|
|
@@ -32,7 +32,7 @@ card_queue = []
|
|
32
32
|
|
33
33
|
|
34
34
|
def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='', tango='', reuse_audio=False,
|
35
|
-
should_update_audio=True, ss_time=0, game_line=None, selected_lines=None, prev_ss_timing=0, start_time=None, end_time=None):
|
35
|
+
should_update_audio=True, ss_time=0, game_line=None, selected_lines=None, prev_ss_timing=0, start_time=None, end_time=None, vad_result=None):
|
36
36
|
update_audio = should_update_audio and (get_config().anki.sentence_audio_field and not
|
37
37
|
last_note.get_field(get_config().anki.sentence_audio_field) or get_config().anki.overwrite_audio)
|
38
38
|
update_picture = (get_config().anki.picture_field and get_config().screenshot.enabled
|
@@ -41,14 +41,17 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
41
41
|
audio_in_anki = ''
|
42
42
|
screenshot_in_anki = ''
|
43
43
|
prev_screenshot_in_anki = ''
|
44
|
+
video_in_anki = ''
|
45
|
+
video = ''
|
44
46
|
screenshot = ''
|
45
47
|
prev_screenshot = ''
|
46
48
|
if reuse_audio:
|
47
49
|
logger.info("Reusing Audio from last note")
|
48
|
-
anki_result = anki_results[game_line.id]
|
50
|
+
anki_result: AnkiUpdateResult = anki_results[game_line.id]
|
49
51
|
audio_in_anki = anki_result.audio_in_anki
|
50
52
|
screenshot_in_anki = anki_result.screenshot_in_anki
|
51
53
|
prev_screenshot_in_anki = anki_result.prev_screenshot_in_anki
|
54
|
+
video_in_anki = anki_result.video_in_anki
|
52
55
|
else:
|
53
56
|
if update_audio:
|
54
57
|
audio_in_anki = store_media_file(audio_path)
|
@@ -56,9 +59,16 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
56
59
|
open_audio_in_external(f"{get_config().audio.anki_media_collection}/{audio_in_anki}")
|
57
60
|
if update_picture:
|
58
61
|
logger.info("Getting Screenshot...")
|
59
|
-
|
62
|
+
if get_config().screenshot.animated:
|
63
|
+
screenshot = ffmpeg.get_anki_compatible_video(video_path, start_time, vad_result.start, vad_result.end, codec='avif', quality=10, fps=12, audio=False)
|
64
|
+
else:
|
65
|
+
screenshot = ffmpeg.get_screenshot(video_path, ss_time, try_selector=get_config().screenshot.use_screenshot_selector)
|
60
66
|
wait_for_stable_file(screenshot)
|
61
67
|
screenshot_in_anki = store_media_file(screenshot)
|
68
|
+
if get_config().anki.video_field:
|
69
|
+
if vad_result:
|
70
|
+
video = ffmpeg.get_anki_compatible_video(video_path, start_time, vad_result.start, vad_result.end, codec='avif', quality=10, fps=12, audio=True)
|
71
|
+
video_in_anki = store_media_file(video)
|
62
72
|
if get_config().anki.previous_image_field and game_line.prev:
|
63
73
|
prev_screenshot = ffmpeg.get_screenshot_for_line(video_path, selected_lines[0].prev if selected_lines else game_line.prev, try_selector=get_config().screenshot.use_screenshot_selector)
|
64
74
|
wait_for_stable_file(prev_screenshot)
|
@@ -68,58 +78,6 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
68
78
|
audio_html = f"[sound:{audio_in_anki}]"
|
69
79
|
image_html = f"<img src=\"{screenshot_in_anki}\">"
|
70
80
|
prev_screenshot_html = f"<img src=\"{prev_screenshot_in_anki}\">"
|
71
|
-
|
72
|
-
|
73
|
-
# Vars for DB update
|
74
|
-
new_audio_path = ''
|
75
|
-
new_screenshot_path = ''
|
76
|
-
new_prev_screenshot_path = ''
|
77
|
-
new_video_path = ''
|
78
|
-
translation = ''
|
79
|
-
anki_audio_path = ''
|
80
|
-
anki_screenshot_path = ''
|
81
|
-
# Move files to output folder if configured
|
82
|
-
if get_config().paths.output_folder and get_config().paths.copy_temp_files_to_output_folder:
|
83
|
-
word_path = os.path.join(get_config().paths.output_folder, sanitize_filename(tango))
|
84
|
-
os.makedirs(word_path, exist_ok=True)
|
85
|
-
|
86
|
-
if audio_path:
|
87
|
-
audio_filename = Path(audio_path).name
|
88
|
-
new_audio_path = os.path.join(word_path, audio_filename)
|
89
|
-
if os.path.exists(audio_path):
|
90
|
-
shutil.copy(audio_path, new_audio_path)
|
91
|
-
if screenshot:
|
92
|
-
screenshot_filename = Path(screenshot).name
|
93
|
-
new_screenshot_path = os.path.join(word_path, screenshot_filename)
|
94
|
-
if os.path.exists(screenshot):
|
95
|
-
shutil.copy(screenshot, new_screenshot_path)
|
96
|
-
if prev_screenshot:
|
97
|
-
prev_screenshot_filename = Path(prev_screenshot).name
|
98
|
-
new_prev_screenshot_path = os.path.join(word_path, "prev_" + prev_screenshot_filename)
|
99
|
-
if os.path.exists(prev_screenshot):
|
100
|
-
shutil.copy(prev_screenshot, new_prev_screenshot_path)
|
101
|
-
|
102
|
-
if video_path and get_config().paths.copy_trimmed_replay_to_output_folder:
|
103
|
-
trimmed_video = ffmpeg.trim_replay_for_gameline(video_path, start_time, end_time, accurate=True)
|
104
|
-
new_video_path = os.path.join(word_path, Path(trimmed_video).name)
|
105
|
-
if os.path.exists(trimmed_video):
|
106
|
-
shutil.copy(trimmed_video, new_video_path)
|
107
|
-
|
108
|
-
if get_config().audio.anki_media_collection:
|
109
|
-
anki_audio_path = os.path.join(get_config().audio.anki_media_collection, audio_in_anki)
|
110
|
-
anki_screenshot_path = os.path.join(get_config().audio.anki_media_collection, screenshot_in_anki)
|
111
|
-
|
112
|
-
# Open to word_path if configured
|
113
|
-
if get_config().paths.open_output_folder_on_card_creation:
|
114
|
-
try:
|
115
|
-
if platform.system() == "Windows":
|
116
|
-
subprocess.Popen(f'explorer "{word_path}"')
|
117
|
-
elif platform.system() == "Darwin":
|
118
|
-
subprocess.Popen(["open", word_path])
|
119
|
-
else:
|
120
|
-
subprocess.Popen(["xdg-open", word_path])
|
121
|
-
except Exception as e:
|
122
|
-
logger.error(f"Error opening output folder: {e}")
|
123
81
|
|
124
82
|
|
125
83
|
# note = {'id': last_note.noteId, 'fields': {}}
|
@@ -129,6 +87,10 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
129
87
|
|
130
88
|
if update_picture and screenshot_in_anki:
|
131
89
|
note['fields'][get_config().anki.picture_field] = image_html
|
90
|
+
|
91
|
+
if video_in_anki:
|
92
|
+
note['fields'][get_config().anki.video_field] = video_in_anki
|
93
|
+
|
132
94
|
if not get_config().screenshot.enabled:
|
133
95
|
logger.info("Skipping Adding Screenshot to Anki, Screenshot is disabled in settings")
|
134
96
|
|
@@ -158,9 +120,9 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
158
120
|
tag_string = " ".join(tags)
|
159
121
|
invoke("addTags", tags=tag_string, notes=[last_note.noteId])
|
160
122
|
|
161
|
-
|
123
|
+
run_new_thread(lambda: check_and_update_note(last_note, note, tags))
|
162
124
|
|
163
|
-
|
125
|
+
word_path = os.path.join(get_config().paths.output_folder, sanitize_filename(tango)) if get_config().paths.output_folder else ''
|
164
126
|
if not reuse_audio:
|
165
127
|
anki_results[game_line.id] = AnkiUpdateResult(
|
166
128
|
success=True,
|
@@ -168,10 +130,81 @@ def update_anki_card(last_note: AnkiCard, note=None, audio_path='', video_path='
|
|
168
130
|
screenshot_in_anki=screenshot_in_anki,
|
169
131
|
prev_screenshot_in_anki=prev_screenshot_in_anki,
|
170
132
|
sentence_in_anki=game_line.text if game_line else '',
|
171
|
-
multi_line=bool(selected_lines and len(selected_lines) > 1)
|
133
|
+
multi_line=bool(selected_lines and len(selected_lines) > 1),
|
134
|
+
video_in_anki=video_in_anki or '',
|
135
|
+
word_path=word_path
|
172
136
|
)
|
137
|
+
# Update GameLine in DB
|
138
|
+
|
139
|
+
# Vars for DB update
|
140
|
+
new_audio_path = ''
|
141
|
+
new_screenshot_path = ''
|
142
|
+
new_prev_screenshot_path = ''
|
143
|
+
new_video_path = ''
|
144
|
+
translation = ''
|
145
|
+
anki_audio_path = ''
|
146
|
+
anki_screenshot_path = ''
|
147
|
+
# Move files to output folder if configured
|
148
|
+
if get_config().paths.output_folder and reuse_audio:
|
149
|
+
anki_result: AnkiUpdateResult = anki_results[game_line.id]
|
150
|
+
previous_word_path = anki_result.word_path
|
151
|
+
if previous_word_path and os.path.exists(previous_word_path):
|
152
|
+
os.makedirs(word_path, exist_ok=True)
|
153
|
+
# Copy all files from previous_word_path to word_path
|
154
|
+
for item in os.listdir(previous_word_path):
|
155
|
+
s = os.path.join(previous_word_path, item)
|
156
|
+
d = os.path.join(word_path, item)
|
157
|
+
if os.path.isdir(s):
|
158
|
+
shutil.copytree(s, d, False, None)
|
159
|
+
else:
|
160
|
+
shutil.copy2(s, d)
|
161
|
+
elif get_config().paths.output_folder and get_config().paths.copy_temp_files_to_output_folder:
|
162
|
+
os.makedirs(word_path, exist_ok=True)
|
163
|
+
if audio_path:
|
164
|
+
audio_filename = Path(audio_path).name
|
165
|
+
new_audio_path = os.path.join(word_path, audio_filename)
|
166
|
+
if os.path.exists(audio_path):
|
167
|
+
shutil.copy(audio_path, new_audio_path)
|
168
|
+
if screenshot:
|
169
|
+
screenshot_filename = Path(screenshot).name
|
170
|
+
new_screenshot_path = os.path.join(word_path, screenshot_filename)
|
171
|
+
if os.path.exists(screenshot):
|
172
|
+
shutil.copy(screenshot, new_screenshot_path)
|
173
|
+
if prev_screenshot:
|
174
|
+
prev_screenshot_filename = Path(prev_screenshot).name
|
175
|
+
new_prev_screenshot_path = os.path.join(word_path, "prev_" + prev_screenshot_filename)
|
176
|
+
if os.path.exists(prev_screenshot):
|
177
|
+
shutil.copy(prev_screenshot, new_prev_screenshot_path)
|
178
|
+
|
179
|
+
if video_path and get_config().paths.copy_trimmed_replay_to_output_folder:
|
180
|
+
trimmed_video = ffmpeg.trim_replay_for_gameline(video_path, start_time, end_time, accurate=True)
|
181
|
+
new_video_path = os.path.join(word_path, Path(trimmed_video).name)
|
182
|
+
if os.path.exists(trimmed_video):
|
183
|
+
shutil.copy(trimmed_video, new_video_path)
|
184
|
+
|
185
|
+
if video:
|
186
|
+
new_video_path = os.path.join(word_path, Path(video).name)
|
187
|
+
if os.path.exists(video):
|
188
|
+
shutil.copy(video, new_video_path)
|
173
189
|
|
174
|
-
|
190
|
+
if get_config().audio.anki_media_collection:
|
191
|
+
anki_audio_path = os.path.join(get_config().audio.anki_media_collection, audio_in_anki)
|
192
|
+
anki_screenshot_path = os.path.join(get_config().audio.anki_media_collection, screenshot_in_anki)
|
193
|
+
|
194
|
+
# Open to word_path if configured
|
195
|
+
if get_config().paths.open_output_folder_on_card_creation:
|
196
|
+
try:
|
197
|
+
if platform.system() == "Windows":
|
198
|
+
subprocess.Popen(f'explorer "{word_path}"')
|
199
|
+
elif platform.system() == "Darwin":
|
200
|
+
subprocess.Popen(["open", word_path])
|
201
|
+
else:
|
202
|
+
subprocess.Popen(["xdg-open", word_path])
|
203
|
+
except Exception as e:
|
204
|
+
logger.error(f"Error opening output folder: {e}")
|
205
|
+
|
206
|
+
logger.info(f"Adding {game_line.id} to Anki Results Dict...")
|
207
|
+
|
175
208
|
GameLinesTable.update(line_id=game_line.id, screenshot_path=new_screenshot_path, audio_path=new_audio_path, replay_path=new_video_path, audio_in_anki=anki_audio_path, screenshot_in_anki=anki_screenshot_path, translation=translation)
|
176
209
|
|
177
210
|
def check_and_update_note(last_note, note, tags=[]):
|
@@ -428,6 +461,7 @@ def update_new_card():
|
|
428
461
|
texthooking_page.reset_checked_lines()
|
429
462
|
else:
|
430
463
|
logger.info("New card(s) detected! Added to Processing Queue!")
|
464
|
+
gsm_state.last_mined_line = game_line
|
431
465
|
card_queue.append((last_card, datetime.now(), lines))
|
432
466
|
texthooking_page.reset_checked_lines()
|
433
467
|
try:
|
@@ -438,13 +472,26 @@ def update_new_card():
|
|
438
472
|
return
|
439
473
|
|
440
474
|
def update_card_from_same_sentence(last_card, lines, game_line):
|
475
|
+
time_elapsed = 0
|
441
476
|
while game_line.id not in anki_results:
|
442
477
|
time.sleep(0.5)
|
478
|
+
time_elapsed += 0.5
|
479
|
+
if time_elapsed > 15:
|
480
|
+
logger.info(f"Timed out waiting for Anki update for card {last_card.noteId}, retrieving new audio")
|
481
|
+
card_queue.append((last_card, datetime.now(), lines))
|
482
|
+
texthooking_page.reset_checked_lines()
|
483
|
+
try:
|
484
|
+
obs.save_replay_buffer()
|
485
|
+
except Exception as e:
|
486
|
+
card_queue.pop(0)
|
487
|
+
logger.error(f"Error saving replay buffer: {e}")
|
488
|
+
return
|
443
489
|
anki_result = anki_results[game_line.id]
|
444
490
|
if anki_result.success:
|
445
491
|
note, last_card = get_initial_card_info(last_card, lines)
|
492
|
+
tango = last_card.get_field(get_config().anki.word_field)
|
446
493
|
update_anki_card(last_card, note=note,
|
447
|
-
game_line=get_mined_line(last_card, lines), reuse_audio=True)
|
494
|
+
game_line=get_mined_line(last_card, lines), reuse_audio=True, tango=tango)
|
448
495
|
else:
|
449
496
|
logger.error(f"Anki update failed for card {last_card.noteId}")
|
450
497
|
notification.send_error_no_anki_update()
|
@@ -307,6 +307,7 @@ class ConfigApp:
|
|
307
307
|
self.word_field_value = tk.StringVar(value=self.settings.anki.word_field)
|
308
308
|
self.previous_sentence_field_value = tk.StringVar(value=self.settings.anki.previous_sentence_field)
|
309
309
|
self.previous_image_field_value = tk.StringVar(value=self.settings.anki.previous_image_field)
|
310
|
+
self.video_field_value = tk.StringVar(value=self.settings.anki.video_field)
|
310
311
|
self.custom_tags_value = tk.StringVar(value=', '.join(self.settings.anki.custom_tags))
|
311
312
|
self.tags_to_check_value = tk.StringVar(value=', '.join(self.settings.anki.tags_to_check))
|
312
313
|
self.add_game_tag_value = tk.BooleanVar(value=self.settings.anki.add_game_tag)
|
@@ -335,7 +336,8 @@ class ConfigApp:
|
|
335
336
|
self.seconds_after_line_value = tk.StringVar(value=str(self.settings.screenshot.seconds_after_line))
|
336
337
|
self.screenshot_timing_value = tk.StringVar(value=self.settings.screenshot.screenshot_timing_setting)
|
337
338
|
self.use_screenshot_selector_value = tk.BooleanVar(value=self.settings.screenshot.use_screenshot_selector)
|
338
|
-
|
339
|
+
self.animated_screenshot_value = tk.BooleanVar(value=self.settings.screenshot.animated)
|
340
|
+
|
339
341
|
# Audio Settings
|
340
342
|
self.audio_enabled_value = tk.BooleanVar(value=self.settings.audio.enabled)
|
341
343
|
self.audio_extension_value = tk.StringVar(value=self.settings.audio.extension)
|
@@ -522,6 +524,7 @@ class ConfigApp:
|
|
522
524
|
word_field=self.word_field_value.get(),
|
523
525
|
previous_sentence_field=self.previous_sentence_field_value.get(),
|
524
526
|
previous_image_field=self.previous_image_field_value.get(),
|
527
|
+
video_field=self.video_field_value.get(),
|
525
528
|
custom_tags=[tag.strip() for tag in self.custom_tags_value.get().split(',') if tag.strip()],
|
526
529
|
tags_to_check=[tag.strip().lower() for tag in self.tags_to_check_value.get().split(',') if tag.strip()],
|
527
530
|
add_game_tag=self.add_game_tag_value.get(),
|
@@ -541,6 +544,7 @@ class ConfigApp:
|
|
541
544
|
),
|
542
545
|
screenshot=Screenshot(
|
543
546
|
enabled=self.screenshot_enabled_value.get(),
|
547
|
+
animated=self.animated_screenshot_value.get(),
|
544
548
|
width=self.screenshot_width_value.get(),
|
545
549
|
height=self.screenshot_height_value.get(),
|
546
550
|
quality=self.screenshot_quality_value.get(),
|
@@ -1304,6 +1308,13 @@ class ConfigApp:
|
|
1304
1308
|
ttk.Entry(anki_frame, textvariable=self.previous_image_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1305
1309
|
self.current_row += 1
|
1306
1310
|
|
1311
|
+
video_img_i18n = anki_i18n.get('video_field', {})
|
1312
|
+
HoverInfoLabelWidget(anki_frame, text=video_img_i18n.get('label', '...'),
|
1313
|
+
tooltip=video_img_i18n.get('tooltip', '...'),
|
1314
|
+
row=self.current_row, column=0)
|
1315
|
+
ttk.Entry(anki_frame, textvariable=self.video_field_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1316
|
+
self.current_row += 1
|
1317
|
+
|
1307
1318
|
tags_i18n = anki_i18n.get('custom_tags', {})
|
1308
1319
|
HoverInfoLabelWidget(anki_frame, text=tags_i18n.get('label', '...'), tooltip=tags_i18n.get('tooltip', '...'),
|
1309
1320
|
row=self.current_row, column=0)
|
@@ -1469,6 +1480,13 @@ class ConfigApp:
|
|
1469
1480
|
ttk.Combobox(screenshot_frame, textvariable=self.screenshot_extension_value, values=['webp', 'avif', 'png', 'jpeg'],
|
1470
1481
|
state="readonly").grid(row=self.current_row, column=1, sticky='EW', pady=2)
|
1471
1482
|
self.current_row += 1
|
1483
|
+
|
1484
|
+
animated_i18n = ss_i18n.get('animated', {})
|
1485
|
+
HoverInfoLabelWidget(screenshot_frame, text=animated_i18n.get('label', '...'), tooltip=animated_i18n.get('tooltip', '...'),
|
1486
|
+
row=self.current_row, column=0)
|
1487
|
+
ttk.Checkbutton(screenshot_frame, variable=self.animated_screenshot_value, bootstyle="round-toggle").grid(
|
1488
|
+
row=self.current_row, column=1, sticky='W', pady=2)
|
1489
|
+
self.current_row += 1
|
1472
1490
|
|
1473
1491
|
ffmpeg_i18n = ss_i18n.get('ffmpeg_options', {})
|
1474
1492
|
HoverInfoLabelWidget(screenshot_frame, text=ffmpeg_i18n.get('label', '...'),
|
@@ -1577,10 +1595,10 @@ class ConfigApp:
|
|
1577
1595
|
preset_options_i18n = ffmpeg_preset_i18n.get('options', {})
|
1578
1596
|
self.ffmpeg_audio_preset_options_map = {
|
1579
1597
|
preset_options_i18n.get('no_reencode', "No Re-encode"): "",
|
1580
|
-
preset_options_i18n.get('fade_in', "Simple Fade-in..."): "-c:a {encoder} -f {format} -af \"afade=t=in:d=0.
|
1581
|
-
preset_options_i18n.get('loudness_norm', "Simple loudness..."): "-c:a {encoder} -f {format} -af \"loudnorm=I=-23:TP=-2,afade=t=in:d=0.
|
1582
|
-
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.
|
1583
|
-
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.
|
1598
|
+
preset_options_i18n.get('fade_in', "Simple Fade-in..."): "-c:a {encoder} -f {format} -af \"afade=t=in:d=0.005\"",
|
1599
|
+
preset_options_i18n.get('loudness_norm', "Simple loudness..."): "-c:a {encoder} -f {format} -af \"loudnorm=I=-23:TP=-2,afade=t=in:d=0.005\"",
|
1600
|
+
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.005\"",
|
1601
|
+
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.005\"",
|
1584
1602
|
preset_options_i18n.get('custom', "Custom"): get_config().audio.custom_encode_settings,
|
1585
1603
|
}
|
1586
1604
|
|
@@ -2107,12 +2125,12 @@ class ConfigApp:
|
|
2107
2125
|
if ai_models and ai_models.gemini_models and ai_models.groq_models:
|
2108
2126
|
if time.time() - ai_models.last_updated > 3600 * 6:
|
2109
2127
|
print("AI models are outdated, fetching new ones.")
|
2110
|
-
|
2128
|
+
self.window.after(100, get_models)
|
2111
2129
|
self.gemini_model_combobox['values'] = ai_models.gemini_models
|
2112
2130
|
self.groq_models_combobox['values'] = ai_models.groq_models
|
2113
2131
|
else:
|
2114
2132
|
print("No AI models found, fetching new ones.")
|
2115
|
-
|
2133
|
+
self.window.after(100, get_models)
|
2116
2134
|
# get_models()
|
2117
2135
|
|
2118
2136
|
def update_models_element(self, frame, row):
|
@@ -247,7 +247,8 @@ class VideoToAudioHandler(FileSystemEventHandler):
|
|
247
247
|
game_line=mined_line,
|
248
248
|
selected_lines=selected_lines,
|
249
249
|
start_time=start_time,
|
250
|
-
end_time=end_time
|
250
|
+
end_time=end_time,
|
251
|
+
vad_result=vad_result
|
251
252
|
)
|
252
253
|
elif get_config().features.notify_on_update and vad_result.success:
|
253
254
|
notification.send_audio_generated_notification(
|
{gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/en_us.json
RENAMED
@@ -182,6 +182,10 @@
|
|
182
182
|
"label": "Previous VoiceLine SS Field:",
|
183
183
|
"tooltip": "Field in Anki for the screenshot of previous line. If Empty, will not populate"
|
184
184
|
},
|
185
|
+
"video_field": {
|
186
|
+
"label": "Video Field:",
|
187
|
+
"tooltip": "Field in Anki for associated videos. This will be AV1 encoded video of the VAD Trimmed Voiceline, if no Voice found, this will be empty."
|
188
|
+
},
|
185
189
|
"custom_tags": {
|
186
190
|
"label": "Add Tags:",
|
187
191
|
"tooltip": "Comma-separated custom tags for the Anki cards."
|
@@ -307,6 +311,10 @@
|
|
307
311
|
"label": "Extension:",
|
308
312
|
"tooltip": "File extension for the screenshot format."
|
309
313
|
},
|
314
|
+
"animated": {
|
315
|
+
"label": "Animated:",
|
316
|
+
"tooltip": "Enable to create an animated screenshot. Will be a webm file encoded with AV1. All settings under this are not applicable with this ON."
|
317
|
+
},
|
310
318
|
"ffmpeg_options": {
|
311
319
|
"label": "FFmpeg Reencode Options:",
|
312
320
|
"tooltip": "Custom FFmpeg options for re-encoding screenshots."
|
{gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/ja_jp.json
RENAMED
@@ -181,6 +181,10 @@
|
|
181
181
|
"label": "前の画像フィールド:",
|
182
182
|
"tooltip": "前のセリフの画像を保存するフィールド。空欄で無効。"
|
183
183
|
},
|
184
|
+
"video_field": {
|
185
|
+
"label": "動画フィールド:",
|
186
|
+
"tooltip": "Ankiの関連動画フィールド。VADトリミングされたボイスラインのAV1エンコード動画です。音声が見つからない場合は空になります。"
|
187
|
+
},
|
184
188
|
"custom_tags": {
|
185
189
|
"label": "追加タグ:",
|
186
190
|
"tooltip": "Ankiカードに追加するカスタムタグ(カンマ区切り)。"
|
@@ -306,6 +310,10 @@
|
|
306
310
|
"label": "拡張子:",
|
307
311
|
"tooltip": "スクリーンショットのファイル形式。"
|
308
312
|
},
|
313
|
+
"animated": {
|
314
|
+
"label": "アニメーション:",
|
315
|
+
"tooltip": "アニメーションスクリーンショットを作成する。AV1でエンコードされたwebmファイルになります。この設定がONの場合、以下の設定は適用されません。"
|
316
|
+
},
|
309
317
|
"ffmpeg_options": {
|
310
318
|
"label": "FFmpeg再エンコード設定:",
|
311
319
|
"tooltip": "スクリーンショットの再エンコードに使用するカスタムFFmpegオプション。"
|
{gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/locales/zh_cn.json
RENAMED
@@ -182,6 +182,10 @@
|
|
182
182
|
"label": "上一句截图字段:",
|
183
183
|
"tooltip": "Anki 中用于上一句截图的字段。如果为空,则不填充。"
|
184
184
|
},
|
185
|
+
"video_field": {
|
186
|
+
"label": "视频字段:",
|
187
|
+
"tooltip": "Anki 中关联视频的字段。这将是VAD修剪语音线的AV1编码视频,如果未找到语音,此字段将为空。"
|
188
|
+
},
|
185
189
|
"custom_tags": {
|
186
190
|
"label": "添加标签:",
|
187
191
|
"tooltip": "Anki 卡片的自定义标签(以逗号分隔)。"
|
@@ -307,6 +311,10 @@
|
|
307
311
|
"label": "扩展名:",
|
308
312
|
"tooltip": "截图格式的文件扩展名。"
|
309
313
|
},
|
314
|
+
"animated": {
|
315
|
+
"label": "动画:",
|
316
|
+
"tooltip": "启用创建动画截图。将是使用AV1编码的webm文件。启用此选项时,以下所有设置均不适用。"
|
317
|
+
},
|
310
318
|
"ffmpeg_options": {
|
311
319
|
"label": "FFmpeg 重编码选项:",
|
312
320
|
"tooltip": "用于重编码截图的自定义 FFmpeg 选项。"
|
@@ -43,16 +43,21 @@ class OBSConnectionManager(threading.Thread):
|
|
43
43
|
logger.info(f"OBS WebSocket not connected. Attempting to reconnect... {e}")
|
44
44
|
gsm_status.obs_connected = False
|
45
45
|
asyncio.run(connect_to_obs())
|
46
|
-
if self.counter % 5 == 0
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
if self.counter % 5 == 0:
|
47
|
+
try:
|
48
|
+
set_fit_to_screen_for_scene_items(get_current_scene())
|
49
|
+
if get_config().obs.turn_off_output_check and self.check_output:
|
50
|
+
replay_buffer_status = get_replay_buffer_status()
|
51
|
+
if replay_buffer_status and self.said_no_to_replay_buffer:
|
52
|
+
self.said_no_to_replay_buffer = False
|
53
|
+
self.counter = 0
|
54
|
+
if gsm_status.obs_connected and not replay_buffer_status and not self.said_no_to_replay_buffer:
|
55
|
+
try:
|
56
|
+
self.check_output()
|
57
|
+
except Exception as e:
|
58
|
+
pass
|
59
|
+
except Exception as e:
|
60
|
+
logger.error(f"Error when running Extra Utils in OBS Health Check, Keeping ConnectionManager Alive: {e}")
|
56
61
|
self.counter += 1
|
57
62
|
|
58
63
|
def stop(self):
|
@@ -463,6 +468,61 @@ def get_current_game(sanitize=False, update=True):
|
|
463
468
|
return gsm_state.current_game
|
464
469
|
|
465
470
|
|
471
|
+
|
472
|
+
def set_fit_to_screen_for_scene_items(scene_name: str):
|
473
|
+
"""
|
474
|
+
Sets all sources in a given scene to "Fit to Screen" (like Ctrl+F in OBS).
|
475
|
+
|
476
|
+
This function fetches the canvas dimensions, then iterates through all scene
|
477
|
+
items in the specified scene and applies a transform that scales them to
|
478
|
+
fit within the canvas while maintaining aspect ratio and centering them.
|
479
|
+
|
480
|
+
Args:
|
481
|
+
scene_name: The name of the scene to modify.
|
482
|
+
"""
|
483
|
+
try:
|
484
|
+
# 1. Get the canvas (base) resolution from OBS video settings
|
485
|
+
video_settings = client.get_video_settings()
|
486
|
+
canvas_width = video_settings.base_width
|
487
|
+
canvas_height = video_settings.base_height
|
488
|
+
|
489
|
+
# 2. Get the list of items in the specified scene
|
490
|
+
scene_items_response = client.get_scene_item_list(scene_name)
|
491
|
+
items = scene_items_response.scene_items if scene_items_response.scene_items else []
|
492
|
+
|
493
|
+
if not items:
|
494
|
+
logger.warning(f"No items found in scene '{scene_name}'.")
|
495
|
+
return
|
496
|
+
|
497
|
+
# 3. Loop through each item and apply the "Fit to Screen" transform
|
498
|
+
for item in items:
|
499
|
+
item_id = item['sceneItemId']
|
500
|
+
source_name = item['sourceName']
|
501
|
+
|
502
|
+
# This transform object is the equivalent of "Fit to Screen"
|
503
|
+
fit_to_screen_transform = {
|
504
|
+
'boundsType': 'OBS_BOUNDS_SCALE_INNER',
|
505
|
+
'alignment': 5, # 5 = Center alignment (horizontal and vertical)
|
506
|
+
'boundsWidth': canvas_width,
|
507
|
+
'boundsHeight': canvas_height,
|
508
|
+
}
|
509
|
+
|
510
|
+
try:
|
511
|
+
client.set_scene_item_transform(
|
512
|
+
scene_name=scene_name,
|
513
|
+
item_id=item_id,
|
514
|
+
transform=fit_to_screen_transform
|
515
|
+
)
|
516
|
+
except obs.error.OBSSDKError as e:
|
517
|
+
logger.error(f"Failed to set transform for source '{source_name}': {e}")
|
518
|
+
|
519
|
+
except obs.error.OBSSDKError as e:
|
520
|
+
# This will catch errors like "scene not found"
|
521
|
+
logger.error(f"An OBS error occurred: {e}")
|
522
|
+
except Exception as e:
|
523
|
+
logger.error(f"An unexpected error occurred: {e}")
|
524
|
+
|
525
|
+
|
466
526
|
def main():
|
467
527
|
start_obs()
|
468
528
|
connect_to_obs()
|
@@ -501,6 +561,8 @@ def main():
|
|
501
561
|
if __name__ == '__main__':
|
502
562
|
from mss import mss
|
503
563
|
logging.basicConfig(level=logging.INFO)
|
564
|
+
connect_to_obs_sync()
|
565
|
+
set_fit_to_screen_for_scene_items(get_current_scene())
|
504
566
|
# main()
|
505
567
|
# connect_to_obs_sync()
|
506
568
|
# img = get_screenshot_PIL(source_name="Display Capture 2", compression=75, img_format='png', width=1280, height=720)
|
{gamesentenceminer-2.14.15 → gamesentenceminer-2.14.17}/GameSentenceMiner/util/configuration.py
RENAMED
@@ -436,6 +436,7 @@ class Anki:
|
|
436
436
|
word_field: str = 'Expression'
|
437
437
|
previous_sentence_field: str = ''
|
438
438
|
previous_image_field: str = ''
|
439
|
+
video_field: str = ''
|
439
440
|
# Initialize to None and set it in __post_init__
|
440
441
|
custom_tags: List[str] = None
|
441
442
|
tags_to_check: List[str] = None
|
@@ -475,6 +476,7 @@ class Screenshot:
|
|
475
476
|
custom_ffmpeg_settings: str = ''
|
476
477
|
custom_ffmpeg_option_selected: str = ''
|
477
478
|
screenshot_hotkey_updates_anki: bool = False
|
479
|
+
animated: bool = False
|
478
480
|
seconds_after_line: float = 1.0
|
479
481
|
use_beginning_of_line_as_screenshot: bool = True
|
480
482
|
use_new_screenshot_logic: bool = False
|
@@ -502,7 +504,7 @@ class Audio:
|
|
502
504
|
beginning_offset: float = -0.5
|
503
505
|
end_offset: float = 0.5
|
504
506
|
pre_vad_end_offset: float = 0.0
|
505
|
-
ffmpeg_reencode_options: str = '-c:a {encoder} -f {format} -af \"afade=t=in:d=0.
|
507
|
+
ffmpeg_reencode_options: str = '-c:a {encoder} -f {format} -af \"afade=t=in:d=0.005\"' if is_windows() else ''
|
506
508
|
ffmpeg_reencode_options_to_use: str = ''
|
507
509
|
external_tool: str = ""
|
508
510
|
anki_media_collection: str = ""
|
@@ -1147,10 +1149,12 @@ class AnkiUpdateResult:
|
|
1147
1149
|
prev_screenshot_in_anki: str = ''
|
1148
1150
|
sentence_in_anki: str = ''
|
1149
1151
|
multi_line: bool = False
|
1152
|
+
video_in_anki: str = ''
|
1153
|
+
word_path: str = ''
|
1150
1154
|
|
1151
1155
|
@staticmethod
|
1152
1156
|
def failure():
|
1153
|
-
return AnkiUpdateResult(success=False, audio_in_anki='', screenshot_in_anki='', prev_screenshot_in_anki='', sentence_in_anki='', multi_line=False)
|
1157
|
+
return AnkiUpdateResult(success=False, audio_in_anki='', screenshot_in_anki='', prev_screenshot_in_anki='', sentence_in_anki='', multi_line=False, video_in_anki='', word_path='')
|
1154
1158
|
|
1155
1159
|
|
1156
1160
|
@dataclass_json
|
@@ -1197,3 +1201,5 @@ is_beangate = os.path.exists("C:/Users/Beangate")
|
|
1197
1201
|
|
1198
1202
|
logger.debug(f"Running in development mode: {is_dev}")
|
1199
1203
|
logger.debug(f"Running on Beangate's PC: {is_beangate}")
|
1204
|
+
|
1205
|
+
logger.info("THE UPDATE WORKED?")
|