Artem Akymenko
0b953d48e8
refactor: heading transforms + dedup moved to shared layer
...
- conversion_planner.py: caps normalization in _build_chapters()
- conversion_executor.py: heading dedup + state machine via headings_equivalent()
- Fixed seg_start_time → chapter_body_start bug in executor
- Removed getattr fallback defaults in both adapters
- Added 4 tests for caps normalization and heading dedup
- Updated ARCHITECTURE_REFACTOR_PLAN.md with deferred WebUI cleanup
2026-07-26 11:41:59 +03:00
Artem Akymenko
f516cf1985
merge: resolve conflicts with origin/main
...
- Import run_tts_segment_loop (used in pyqt/conversion.py)
- Use build_tts_context() instead of manual _MergeJob + TTSContext
- Drop unused AudioSink import
2026-07-24 18:34:49 +00:00
Artem Akymenko
3857c27aae
refactor: clean unused imports (ruff F401/F811), fix build_tts_context defaults
...
- Remove 77 unused imports across domain/application/runner files via ruff
- Add # noqa: F401 to re-exports used by tests and debug_tts_runner
- Fix build_tts_context: usage_counter uses 'is not None' instead of truthiness
- Fix test assertions: compiled rules use 'replacement' key not 'pronunciation'
- Add re-exports: _compile_pronunciation_rules, _merge_pronunciation_overrides
2026-07-24 21:26:36 +03:00
Artem Akymenko
7ed2addb11
refactor: add build_metadata_payload() to domain, unify metadata assembly in both UIs
2026-07-24 21:26:21 +03:00
Artem Akymenko
cfc7de7abf
refactor: unify PUNCTUATION constants in domain/split_pattern.py
2026-07-24 19:17:39 +03:00
Artem Akymenko
654c395943
refactor: move sanitize_name_for_os to domain/output_paths.py
2026-07-24 19:17:39 +03:00
Artem Akymenko
d1a84cfb8b
refactor: move voice marker functions to domain/voice_markers.py
2026-07-24 19:17:38 +03:00
Artem Akymenko
332934c0cf
test: tests for apply_overrides, LLM mode, usage_counter, chunk_groups
2026-07-24 19:17:38 +03:00
Artem Akymenko
c79838a5a1
fix: chunk_groups_by_chapter in planner, chunks assigned to correct chapter
2026-07-24 19:17:38 +03:00
Artem Akymenko
d51a9118e4
fix: apply_overrides, LLM mode check, usage_counter in service
2026-07-24 19:17:38 +03:00
Artem Akymenko
3311bef2f7
feat: EPUB3 finalizer in service, extraction in ConversionPlan
2026-07-24 19:17:37 +03:00
Artem Akymenko
4123cadd87
feat: m4b finalizer in service (embed_m4b_metadata)
2026-07-24 19:17:37 +03:00
Artem Akymenko
2f83d10a1e
feat: per-chapter subtitle writer in executor
2026-07-24 19:17:37 +03:00
Artem Akymenko
a1241ee9ca
refactor: word substitution in planner, add planner tests
2026-07-24 19:17:37 +03:00
Artem Akymenko
0ee5bb0496
refactor: config objects for feature toggles in ConversionRequest
2026-07-24 19:17:36 +03:00
Artem Akymenko
7d28b7eb52
test: mock subprocess.Popen in test_executor_m4b_forces_merge to eliminate ffmpeg dependency
2026-07-24 19:17:36 +03:00
Deniz Şafak
9201f58770
Add k0sm0naft to GitHub funding list
2026-07-23 16:27:54 +03:00
Deniz Şafak
6274a02d5e
Fix empty voice list when launched via desktop shortcut
...
PluginManager.discover() used a relative path 'plugins', which resolved
against the CWD. When launched from a desktop shortcut the CWD is ~, so
the plugins directory was never found and no voices appeared in the list.
Fall back to the project-relative plugins path when the default relative
path doesn't resolve.
2026-07-23 03:55:07 +03:00
Deniz Şafak
342ea0dfac
Fix spaCy unknown language error: map Kokoro single-letter codes to Language enum in get_spacy_model
2026-07-23 03:33:06 +03:00
Deniz Şafak
27f88b759d
Fix spurious HF HEAD requests: return early on cache hit in tracked_hf_hub_download
2026-07-23 03:26:58 +03:00
Deniz Şafak
dbcbb1c8a9
Fix NameError: add missing 'from pathlib import Path' in pyqt/conversion.py
2026-07-23 03:18:51 +03:00
Deniz Şafak
bd99ee1ba1
fix: subtitle FakeToken split, missing run_tts_segment_loop import
...
- subtitle_generation: split multi-sentence FakeToken into separate entries
- conversion.py: add missing run_tts_segment_loop import
No changes to spacy_utils or Language enum.
2026-07-23 03:15:21 +03:00
Deniz Şafak
d5cddb9749
fix: pass mock job object to merge_pronunciation_overrides instead of positional args
2026-07-23 02:33:18 +03:00
Deniz Şafak
ec55918b04
fix: add load_single_voice to Pipeline wrapper to prevent formula string being used as download filename
2026-07-23 02:28:41 +03:00
Deniz Şafak
14913b45e9
fix: import importlib.util explicitly (not auto-loaded in Python 3.12) — broke plugin loading, causing empty voice lists
2026-07-23 02:17:46 +03:00
Deniz Şafak
a0fdabd81f
fix: suppress harmless Qt portal registration warning on Linux
2026-07-23 01:42:41 +03:00
Deniz Şafak
473631b84e
fix: use theme-aware GREY_BACKGROUND for word substitutions instructions label
2026-07-23 01:41:13 +03:00
Deniz Şafak
0f5003dfdd
fix: add missing imports for get_resource_path and load_integration_settings
2026-07-23 01:37:50 +03:00
Artem Akymenko
fcec4e9fe5
fix: test_stretch_reduces_duration — remove stale self param, fix mock data size, fix atempo assertion
2026-07-22 15:32:18 +03:00
Artem Akymenko
72d5e3d1db
fix: add keys() method to VoiceCache for resolve_intro compatibility
2026-07-22 15:31:43 +03:00
Artem Akymenko
d3682e7672
refactor: dynamic ConversionRequest validation, remove 'or default' from adapters
...
- __post_init__: _apply_none_defaults() iterates dataclasses.fields() dynamically
- _NUMERIC_CONSTRAINTS and _ENUM_CONSTRAINTS dicts replace per-field if chains
- Both adapters pass values as-is (no 'or default' fallbacks)
- 18 validation tests + updated adapter tests for Enum assertions
2026-07-22 11:33:44 +00:00
Artem Akymenko
0805e9fdae
refactor: Language Enum with ISO codes
...
- Language enum: en-US, en-GB, es, fr, hi, it, ja, pt-BR, zh
- Engine-specific mappings (kokoro → single-letter) live in pipeline_factory and synthesize
- spacy_utils uses Language enum keys for model mapping
- split_pattern uses Language enum properties (is_cjk)
- Updated all tests to use ISO codes
2026-07-22 10:54:39 +00:00
Artem Akymenko
4aef73ff85
refactor: remove infrastructure enum duplicates
...
- SubtitleFormat/SubtitleMode now only in domain/enums.py
- Added VTT to SubtitleFormat
- Renamed SENTENCE_HIGHLIGHTING → SENTENCE_HIGHLIGHT for consistency
- Infrastructure subtitle_writer imports from domain
2026-07-22 09:16:40 +00:00
Artem Akymenko
f6a8008f51
refactor: typed Enums for format/mode fields
...
- SubtitleMode, OutputFormat, SaveMode, SubtitleFormat, InputFormat
- Properties: dot_ext, is_lossless, is_book, is_subtitle
- from_str/from_path class methods with normalization
- Updated domain and application layers to use Enums
- 17 new tests for enum validation and properties
2026-07-22 09:01:50 +00:00
Artem Akymenko
dc5257252f
refactor: run_tts_segment_loop also accepts SynthParams
...
- Reduces from 14 params to 5 unique params + SynthParams
- synthesize_text now passes params through cleanly
- PyQt intro/outro direct calls updated
2026-07-22 08:28:19 +00:00
Artem Akymenko
c4cebb8822
refactor: SynthParams dataclass for synthesize_text
...
- Frozen dataclass in domain/conversion_engine.py with common params
- synthesize_text now takes params=SynthParams + unique kwargs
- Executor, PyQt legacy, WebUI legacy, and tests updated
- Adding new common params now only requires changing the dataclass
2026-07-22 08:21:45 +00:00
Artem Akymenko
93f5a46485
refactor: deduplicate synth params in executor
...
- Compute use_spacy and effective_subtitle_mode once instead of 6x each
- Reduces repeated ternary expressions across synthesize_text calls
2026-07-22 11:06:14 +03:00
Artem Akymenko
5f169a4921
refactor: replace executor _slugify with domain sanitize_filename_for_chapter
...
- Use existing domain function instead of duplicated local implementation
- Domain version includes OS-specific sanitization
2026-07-22 11:06:14 +03:00
Artem Akymenko
df5705779e
refactor: extract ConversionCancelled to conversion_ports
...
- Single definition in application layer
- Both adapters import from ports instead of defining locally
2026-07-22 11:06:14 +03:00
Artem Akymenko
d0fe221176
refactor: ConversionPlan.request forward ref
...
- request type: Any → ConversionRequest via TYPE_CHECKING
2026-07-22 07:31:46 +00:00
Artem Akymenko
17700426fd
clean: dead code removal + unused imports
...
- executor: remove dead subtitle_writer stub (lines 121-125)
- executor: replace getattr with direct field access on ResolvedVoice
- service: remove duplicate split_pattern import
- service: remove unused import time
- planner: remove unused import os
- adapters: remove unused import threading, time
2026-07-22 07:21:23 +00:00
Artem Akymenko
16b3f7d8a8
fix: clean direct_text in planner + remove redundant if/else
...
- _extract_source_text now applies clean_text() to direct_text (was skipped)
- _parse_chapters simplified: identical branches collapsed to single call
2026-07-22 07:05:50 +00:00
Artem Akymenko
1a3741ec50
fix: max_subtitle_words default 5 → 50
...
All UI layers use 50 (settings, Job, Thread, adapters). The value 5 was
incorrect and only masked by adapter fallbacks.
2026-07-21 14:58:58 +03:00
Artem Akymenko
7f317ca784
test: adapter field mapping + import layering tests
...
- 28 adapter tests (WebUI + PyQt): field mapping, events, provider, resolver
- 15 import/layering tests: no PyQt/WebUI in app layer, all models importable
2026-07-21 11:47:46 +00:00
Artem Akymenko
d0e42ee691
fix: executor subtitle_writer leak + adapter Path/None-default fixes
...
- executor: manage subtitle_writer via ExitStack (stack.callback)
- executor: remove manual subtitle_writer.close()
- WebUI adapter: wrap source_path, output_folder, cover_image_path in Path()
- WebUI adapter: remove unused threading/time imports
- PyQt adapter: fix getattr(attr, None) or default for 4 fields
2026-07-21 11:47:36 +00:00
Artem Akymenko
b1392084e1
chore: add .coverage to .gitignore
2026-07-21 09:35:36 +00:00
Artem Akymenko
71916aa39f
fix: conversion_service import bug + coverage tests
...
Fix import error in _prepare_tts_context:
- apply_normalization_overrides doesn't exist in domain.normalization
- merge_pronunciation_overrides expects job-like object, not two lists
- Use _MockJob adapter to bridge ConversionRequest to existing API
Add test_application_coverage.py (23 tests):
- ConversionService: simple, logs, cancellation, empty text, multi-chapter, intro/outro, error
- OutputLayoutService: custom folder, source path, project, merged path, chapter path, should_merge
- Executor gaps: no layout, m4b, separate chapters, no intro/outro, voice fallback, silence
Coverage: 80% -> 92%
2026-07-21 09:34:47 +00:00
Artem Akymenko
4c4434c309
fix: sanitize_output_stem signature + audio_sink import
...
Two pre-existing bugs found during test coverage analysis:
1. sanitize_output_stem() only accepted 1 arg but resolve_project_layout
passed 2 args (name, index) via sanitize_fn parameter.
Fix: added optional index parameter to sanitize_output_stem.
2. audio_sink.py imported get_internal_cache_path from
abogen.infrastructure.cache which doesn't exist.
Fix: import from abogen.utils where the function lives.
2026-07-21 09:18:51 +00:00
Artem Akymenko
7973de3868
feat: ConversionService
...
Main orchestrator for the conversion flow. Both UIs call run_conversion().
Functions:
- run_conversion(request, events, pipeline_provider, voice_resolver) -> ConversionResult
- _prepare_tts_context(request, events) -> TTSContext
The service ties together planner, executor, and finalizers.
2026-07-21 11:30:15 +03:00
Artem Akymenko
fd659d0f4f
feat: PyQt adapter
...
Converts PyQt ConversionThread to ConversionRequest for the application layer.
Functions:
- build_conversion_request_from_thread(thread) -> ConversionRequest
- PyQtEvents: wraps thread signals for logging, progress, cancellation
- PyQtPipelineProvider: wraps existing backend
- PyQtVoiceResolver: wraps load_voice_cached
Subtitle file/timestamp special paths remain in ConversionThread.run().
2026-07-21 11:29:47 +03:00