diff --git a/abogen/infrastructure/subtitle_writer.py b/abogen/infrastructure/subtitle_writer.py index d283e38..e8f8d63 100644 --- a/abogen/infrastructure/subtitle_writer.py +++ b/abogen/infrastructure/subtitle_writer.py @@ -220,8 +220,10 @@ class AssWriter(SubtitleWriter): style = "Default" if self.config.mode == SubtitleMode.SENTENCE_HIGHLIGHT: - # Add karaoke tags for highlighting - text = self._add_karaoke_tags(text) + # Entries from process_subtitle_tokens already carry per-word + # {\kf...} timing; only synthesize simplified tags when absent. + if "{\\k" not in text: + text = self._add_karaoke_tags(text) style = "Highlight" alignment_tag = r"{\an5}" if self._is_centered else "" @@ -248,6 +250,19 @@ class AssWriter(SubtitleWriter): return f"{hours}:{minutes:02d}:{secs:05.2f}" +def _coerce_mode(mode: str) -> SubtitleMode: + """Parse a subtitle mode, tolerating word-count strings like "5 words". + + Word-count modes are grouped upstream (subtitle_generation) and the writer + only branches on SubtitleMode.SENTENCE_HIGHLIGHT, so any non-highlight + fallback is behaviorally equivalent for the writers. + """ + try: + return SubtitleMode(mode) + except ValueError: + return SubtitleMode.SENTENCE + + def create_subtitle_writer( path: Path, format: str, @@ -257,7 +272,7 @@ def create_subtitle_writer( ) -> SubtitleWriter: """Factory function to create subtitle writer.""" fmt = SubtitleFormat(format.lower()) - mode = SubtitleMode(mode) + mode = _coerce_mode(mode) align = SubtitleAlignment(alignment.lower()) config = SubtitleConfig( diff --git a/abogen/pyqt/gui.py b/abogen/pyqt/gui.py index 3e7ecee..46b0d93 100644 --- a/abogen/pyqt/gui.py +++ b/abogen/pyqt/gui.py @@ -1019,6 +1019,7 @@ class abogen(QWidget): self.selected_lang = ( language_for_voice_id(entry[0]) if entry and entry[0] else Language.EN_US ) + self.update_subtitle_options_availability() if self.save_option == "Choose output folder" and self.selected_output_folder: self.save_path_label.setText(self.selected_output_folder) self.save_path_row_widget.show() diff --git a/tests/test_subtitle_writer.py b/tests/test_subtitle_writer.py index 82a0a28..78f8bda 100644 --- a/tests/test_subtitle_writer.py +++ b/tests/test_subtitle_writer.py @@ -177,6 +177,19 @@ class TestAssWriter: assert "Highlight" in content assert r"{\k100}" in content + def test_highlight_mode_preserves_existing_karaoke_tags(self, tmp_path): + path = tmp_path / "test.ass" + config = SubtitleConfig( + format=SubtitleFormat.ASS, + mode=SubtitleMode.SENTENCE_HIGHLIGHT, + ) + writer = AssWriter(path, config) + writer.write_entry(start=0.0, end=1.0, text=r"{\kf20}Hello {\kf20}world.") + writer.close() + content = path.read_text() + assert r"{\kf20}Hello {\kf20}world." in content + assert r"{\k100}" not in content + def test_centered_alignment(self, tmp_path): path = tmp_path / "test.ass" config = SubtitleConfig( @@ -243,6 +256,12 @@ class TestCreateSubtitleWriter: with pytest.raises(ValueError): create_subtitle_writer(path, "xyz", "Line") + def test_word_count_mode(self, tmp_path): + path = tmp_path / "test.srt" + writer = create_subtitle_writer(path, "srt", "5 words", max_words=5) + assert isinstance(writer, SrtWriter) + writer.close() + # =================================================================== # Context manager