Compare commits
No commits in common. "main" and "v19.0" have entirely different histories.
2 changed files with 24 additions and 59 deletions
83
main.py
83
main.py
|
|
@ -115,7 +115,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.video_first_lang = "English First (en -> es)"
|
||||
self.video_repeats_count = "3"
|
||||
self.video_pause_duration = "4.0"
|
||||
self.default_deck_name = "Trainer" # Unified structural configuration fallback
|
||||
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
|
@ -133,8 +132,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.video_repeats_count = row[1]
|
||||
elif row[0] == "video_pause_duration":
|
||||
self.video_pause_duration = row[1]
|
||||
elif row[0] == "default_deck_name":
|
||||
self.default_deck_name = row[1]
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to read application settings from database: {e}")
|
||||
finally:
|
||||
|
|
@ -154,8 +151,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.video_repeats_count = value
|
||||
elif key == "video_pause_duration":
|
||||
self.video_pause_duration = value
|
||||
elif key == "default_deck_name":
|
||||
self.default_deck_name = value
|
||||
except Exception as e:
|
||||
print(f"❌ Critical: Failed to save setting '{key}': {e}")
|
||||
finally:
|
||||
|
|
@ -285,7 +280,7 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.input_tags.setPlaceholderText("e.g., irregular_er boots_verb")
|
||||
|
||||
self.input_deck_tag = QLineEdit()
|
||||
self.input_deck_tag.setPlaceholderText("Overrides System Default Workspace Deck")
|
||||
self.input_deck_tag.setPlaceholderText("Anki Sub-deck Hierarchy")
|
||||
|
||||
button_qss = """
|
||||
QPushButton {
|
||||
|
|
@ -362,7 +357,7 @@ class SpanishTrainerApp(QMainWindow):
|
|||
form_layout.addRow("Classification Profile:", self.combo_type)
|
||||
form_layout.addRow("Source Context ID (Raw):", self.input_context)
|
||||
form_layout.addRow("Anki Note Tags:", self.input_tags)
|
||||
form_layout.addRow("<b>Target Deck Scope (Optional):</b>", self.input_deck_tag)
|
||||
form_layout.addRow("<b>Target Deck Scope:</b>", self.input_deck_tag)
|
||||
|
||||
crud_buttons = QHBoxLayout()
|
||||
self.btn_save = QPushButton("➕ Create Pair")
|
||||
|
|
@ -518,11 +513,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
video_layout.addWidget(self.line_video_dir)
|
||||
video_layout.addWidget(btn_browse_video)
|
||||
|
||||
# New Workspace Target Settings Directive Entry
|
||||
self.line_default_deck = QLineEdit(self.default_deck_name)
|
||||
self.line_default_deck.setPlaceholderText("e.g., Spanish::Aula_Plus_1")
|
||||
self.line_default_deck.textChanged.connect(lambda v: self.save_setting_to_db("default_deck_name", v.strip()))
|
||||
|
||||
self.combo_first_lang = QComboBox()
|
||||
self.combo_first_lang.addItems(["English First (en -> es)", "Spanish First (es -> en)"])
|
||||
self.combo_first_lang.setCurrentText(self.video_first_lang)
|
||||
|
|
@ -538,7 +528,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
|
||||
form_layout.addRow("<b>Anki Deck Export Destination:</b>", anki_layout)
|
||||
form_layout.addRow("<b>Video Assembly Output Target:</b>", video_layout)
|
||||
form_layout.addRow("<b>Default Target Deck String:</b>", self.line_default_deck)
|
||||
form_layout.addRow("<b>Introductory Anchor Audio Language:</b>", self.combo_first_lang)
|
||||
form_layout.addRow("<b>Target Translation Loop Multiplier (Repeats):</b>", self.spin_video_repeats)
|
||||
form_layout.addRow("<b>User Recall Repetition Frame Intermission (Seconds):</b>", self.spin_pause_duration)
|
||||
|
|
@ -632,6 +621,7 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.lbl_card_text.setText(self.current_active_en_text)
|
||||
self.btn_flip_card.setText("👁️ Reveal Translation")
|
||||
|
||||
# --- t.notes (record[5]) has been intentionally omitted from this layout context ---
|
||||
meta_str = f"Link ID: {record[0]} | Context: {record[3] or 'N/A'}"
|
||||
if record[4]:
|
||||
meta_str += f" | Tags: {record[4]}"
|
||||
|
|
@ -686,10 +676,6 @@ class SpanishTrainerApp(QMainWindow):
|
|||
(Card 2) forward-reverse pairs cleanly. Explicitly maps 4 fields: EnglishText,
|
||||
EnglishAudio, SpanishText, SpanishAudio. Context and notes are fully removed.
|
||||
"""
|
||||
# Architectural Fallback: If pool is empty, run an internal update pass first to grab current matrix records
|
||||
if not self.flashcard_ids_pool:
|
||||
self.refresh_review_table()
|
||||
|
||||
targets = self.flashcard_ids_pool
|
||||
if not targets:
|
||||
QMessageBox.warning(self, "Export Aborted", "The active flashcard pool filter is completely empty. Nothing to export.")
|
||||
|
|
@ -760,21 +746,11 @@ class SpanishTrainerApp(QMainWindow):
|
|||
css='.card { font-family: arial; font-size: 20px; text-align: center; background-color: #fafafa; padding: 25px; border-radius: 8px; }'
|
||||
)
|
||||
|
||||
# --- RESTRUCTURED STRINGS SAFEGUARD BLOCK ---
|
||||
# Safeguard checks to normalize index 6 data entry and prevent generation string crashes
|
||||
raw_deck_entry = records[0][6]
|
||||
if raw_deck_entry and str(raw_deck_entry).strip():
|
||||
deck_name_fallback = str(raw_deck_entry).strip()
|
||||
else:
|
||||
deck_name_fallback = self.default_deck_name if self.default_deck_name else "Trainer"
|
||||
|
||||
# Explicitly ensure the Anki namespace structural hierarchy sequence is intact
|
||||
full_deck_string = f"Spanish::{deck_name_fallback}" if "Spanish::" not in deck_name_fallback else deck_name_fallback
|
||||
|
||||
anki_deck = genanki.Deck(DECK_ID, full_deck_string)
|
||||
deck_name_fallback = records[0][6] if records[0][6] else "Castilian Voice Trainer"
|
||||
anki_deck = genanki.Deck(DECK_ID, f"Spanish::{deck_name_fallback}")
|
||||
media_files_bundle = []
|
||||
|
||||
print(f"📦 Assembling Anki audio package for {len(records)} notes under deck: {full_deck_string}...")
|
||||
print(f"📦 Assembling Anki audio package for {len(records)} notes...")
|
||||
|
||||
for row in records:
|
||||
tx_id, es_text, en_text, context, tags, notes, deck_group = row
|
||||
|
|
@ -816,6 +792,8 @@ class SpanishTrainerApp(QMainWindow):
|
|||
if context:
|
||||
tag_list.append(str(context).replace(" ", "_").replace(".", "_"))
|
||||
|
||||
# Populate note fields sequentially matching model specification:
|
||||
# EnglishText, EnglishAudio, SpanishText, SpanishAudio
|
||||
anki_note = genanki.Note(
|
||||
model=spanish_model,
|
||||
fields=[
|
||||
|
|
@ -828,28 +806,19 @@ class SpanishTrainerApp(QMainWindow):
|
|||
)
|
||||
anki_deck.add_note(anki_note)
|
||||
|
||||
# Output file name normalization optimization to sweep unmapped character sets
|
||||
safe_file_name = deck_name_fallback.replace('::', '_').replace('/', '_').strip()
|
||||
export_output_path = os.path.join(self.anki_export_dir, f"{safe_file_name}.apkg")
|
||||
# Output compilation assembly
|
||||
export_output_path = os.path.join(self.anki_export_dir, f"{deck_name_fallback.replace('::', '_')}.apkg")
|
||||
|
||||
try:
|
||||
package = genanki.Package(anki_deck)
|
||||
package.media_files = list(set(media_files_bundle))
|
||||
package.write_to_file(export_output_path)
|
||||
package = genanki.Package(anki_deck)
|
||||
package.media_files = list(set(media_files_bundle)) # Excludes duplicate track instances
|
||||
package.write_to_file(export_output_path)
|
||||
|
||||
print(f"✅ Success! Balanced text-audio cards exported cleanly: {export_output_path}")
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Anki Package Compiled",
|
||||
f"Successfully compiled {len(records)} balanced text-audio translation flashcard nodes.\n\nDestination:\n{export_output_path}"
|
||||
)
|
||||
except Exception as export_err:
|
||||
print(f"❌ Genanki Write Failure Exception Error: {export_err}")
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"Export Failure Error",
|
||||
f"The packaging sub-engine failed to write file to disk:\n{export_err}"
|
||||
)
|
||||
print(f"✅ Success! Balanced text-audio cards exported cleanly: {export_output_path}")
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Anki Package Compiled",
|
||||
f"Successfully compiled {len(records)} balanced text-audio translation flashcard nodes.\n\nDestination:\n{export_output_path}"
|
||||
)
|
||||
|
||||
def handle_export_video_assets(self):
|
||||
pass
|
||||
|
|
@ -871,12 +840,9 @@ class SpanishTrainerApp(QMainWindow):
|
|||
""", (self.input_text_en.toPlainText().strip(), self.combo_type.currentText(), self.input_context.text().strip()))
|
||||
en_id = cursor.lastrowid
|
||||
|
||||
# Pulls from self.input_deck_tag if typed, cleanly defaults to global persistent variable self.default_deck_name
|
||||
target_deck = self.input_deck_tag.text().strip() or self.default_deck_name
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO translations (source_phrase_id, target_phrase_id, deck_name, notes, tags) VALUES (?, ?, ?, ?, ?)
|
||||
""", (es_id, en_id, target_deck, self.input_grammar_note.toPlainText().strip(), self.input_tags.text().strip()))
|
||||
""", (es_id, en_id, self.input_deck_tag.text().strip() or "General", self.input_grammar_note.toPlainText().strip(), self.input_tags.text().strip()))
|
||||
tx_id = cursor.lastrowid
|
||||
|
||||
conn.commit()
|
||||
|
|
@ -915,14 +881,11 @@ class SpanishTrainerApp(QMainWindow):
|
|||
WHERE id = ?
|
||||
""", (self.input_text_en.toPlainText().strip(), self.combo_type.currentText(), self.input_context.text().strip(), self.current_sandbox_en_id))
|
||||
|
||||
# Updated field configuration using system preferences cache fallback assignment
|
||||
target_deck = self.input_deck_tag.text().strip() or self.default_deck_name
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE translations
|
||||
SET deck_name = ?, notes = ?, tags = ?
|
||||
WHERE translation_id = ?
|
||||
""", (target_deck, self.input_grammar_note.toPlainText().strip(), self.input_tags.text().strip(), int(tx_id_str)))
|
||||
""", (self.input_deck_tag.text().strip() or "General", self.input_grammar_note.toPlainText().strip(), self.input_tags.text().strip(), int(tx_id_str)))
|
||||
|
||||
conn.commit()
|
||||
except Exception as e:
|
||||
|
|
@ -1075,7 +1038,7 @@ class SpanishTrainerApp(QMainWindow):
|
|||
self.combo_type.setCurrentText(str(record[3]) if record[3] else "phrase")
|
||||
self.input_context.setText(str(record[4]) if record[4] else "")
|
||||
self.input_tags.setText(str(record[7]) if record[7] is not None else "")
|
||||
self.input_deck_tag.setText(str(record[5]) if record[5] else "")
|
||||
self.input_deck_tag.setText(str(record[5]) if record[5] else "General")
|
||||
self.input_grammar_note.setPlainText(str(record[6]) if record[6] is not None else "")
|
||||
self.current_sandbox_es_id = record[8]
|
||||
self.current_sandbox_en_id = record[9]
|
||||
|
|
@ -1101,6 +1064,8 @@ class SpanishTrainerApp(QMainWindow):
|
|||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Spanish Voice Trainer")
|
||||
app.setOrganizationName("Oxnee Pty. Ltd.")
|
||||
window = SpanishTrainerApp()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
Binary file not shown.
Loading…
Reference in a new issue