|
| 1 | +# GoSubtitle AI Coding Agent Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +GoSubtitle is a PyQt6 desktop application that converts Movie XML files (containing TTS data) to SRT subtitle format. It features dual interface modes: GUI for interactive editing and console mode for batch processing/automation. |
| 6 | + |
| 7 | +## Architecture Pattern |
| 8 | + |
| 9 | +The codebase follows a clean 3-layer architecture: |
| 10 | + |
| 11 | +- **Presentation Layer**: `modules/window.py` (GUI), `modules/console.py` (CLI) |
| 12 | +- **Business Logic**: `modules/subtitle_processor.py` (core XML parsing, subtitle processing) |
| 13 | +- **Utilities**: `helpers.py`, `modules/parameters.py` (command-line parsing) |
| 14 | + |
| 15 | +**Key principle**: All subtitle processing logic lives in `SubtitleProcessor` class. GUI and console are thin clients that delegate to this core engine. |
| 16 | + |
| 17 | +## Entry Point & Mode Detection |
| 18 | + |
| 19 | +`main.py` automatically detects execution context: |
| 20 | + |
| 21 | +- Console available → console mode via `Console` class |
| 22 | +- No console OR `-g/--gui` flag → GUI mode via `MainWindow` |
| 23 | +- Uses `helpers.has_console()` with Windows-specific `ctypes.windll.kernel32.GetConsoleWindow()` |
| 24 | + |
| 25 | +## Critical Development Patterns |
| 26 | + |
| 27 | +### UI File Loading |
| 28 | + |
| 29 | +UI files are loaded from `ui/` directory using `pathlib` for cross-platform compatibility: |
| 30 | + |
| 31 | +```python |
| 32 | +BASE_DIR = Path(__file__).resolve().parent.parent |
| 33 | +UI_DIR = BASE_DIR / "ui" |
| 34 | +uic.loadUi(str(UI_DIR / "main_window.ui"), self) |
| 35 | +``` |
| 36 | + |
| 37 | +### Frame-Based Timing System |
| 38 | + |
| 39 | +All timing calculations use **frames at 24 FPS** (hardcoded constant): |
| 40 | + |
| 41 | +- XML contains frame numbers, not timestamps |
| 42 | +- `SubtitleProcessor.format_time()` converts frames → SRT timestamp format |
| 43 | +- Offset operations work in frame units |
| 44 | + |
| 45 | +### Subtitle Processing Pipeline |
| 46 | + |
| 47 | +1. **Parse XML**: Extract TTS sound elements with `tts='1'` attribute |
| 48 | +2. **Merge Overlapping**: Combine subtitles with overlapping time ranges |
| 49 | +3. **Smart Splitting**: Break long subtitles by sentence boundaries + word count limits |
| 50 | +4. **Time Distribution**: Calculate timing based on `words_per_second` rate |
| 51 | + |
| 52 | +### Command-Line Integration |
| 53 | + |
| 54 | +`Parameters` class handles argparse with custom post-processing: |
| 55 | + |
| 56 | +- Speaker replacements: `"old:new"` format → dictionary mapping |
| 57 | +- Multiple `-r` flags supported for batch replacements |
| 58 | +- Uses `getattr(self.args, param_name)` pattern for parameter access |
| 59 | + |
| 60 | +## Development Workflows |
| 61 | + |
| 62 | +### Building Executables |
| 63 | + |
| 64 | +PyInstaller spec generates TWO executables: |
| 65 | + |
| 66 | +```bash |
| 67 | +pyinstaller GoSubtitle.spec |
| 68 | +# Creates: dist/GoSubtitle.exe (GUI) and dist/GoSubtitle_CLI.exe (console) |
| 69 | +``` |
| 70 | + |
| 71 | +Spec includes UI and assets folders as data files. |
| 72 | + |
| 73 | +### Testing Subtitle Processing |
| 74 | + |
| 75 | +Use console mode for quick validation: |
| 76 | + |
| 77 | +```bash |
| 78 | +python main.py -f test.xml --verbose # Shows statistics |
| 79 | +python main.py -f test.xml -o 24 -r "old:new" --max-words 15 |
| 80 | +``` |
| 81 | + |
| 82 | +### Logging Configuration |
| 83 | + |
| 84 | +Each module configures its own logger: |
| 85 | + |
| 86 | +```python |
| 87 | +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
| 88 | +logger = logging.getLogger(__name__) |
| 89 | +``` |
| 90 | + |
| 91 | +## Key Configuration Constants |
| 92 | + |
| 93 | +In `SubtitleProcessor`: |
| 94 | + |
| 95 | +- `FPS = 24`: Fixed frame rate (do not make configurable without XML format changes) |
| 96 | +- `DEFAULT_MAX_WORDS_PER_LINE = 10`: Subtitle splitting threshold |
| 97 | +- `DEFAULT_WORDS_PER_SECOND = 2.5`: Speaking rate for timing calculations |
| 98 | +- `MIN_SUBTITLE_DURATION = 0.5`: Minimum subtitle duration in seconds |
| 99 | + |
| 100 | +## Expected XML Format |
| 101 | + |
| 102 | +```xml |
| 103 | +<root duration="[total_frames]"> |
| 104 | + <sound tts="1"> |
| 105 | + <start>[start_frame]</start> |
| 106 | + <stop>[stop_frame]</stop> |
| 107 | + <ttsdata> |
| 108 | + <text>[subtitle_text]</text> |
| 109 | + <voice>[speaker_name]</voice> |
| 110 | + </ttsdata> |
| 111 | + </sound> |
| 112 | +</root> |
| 113 | +``` |
| 114 | + |
| 115 | +## Module Import Pattern |
| 116 | + |
| 117 | +Uses `__init__.py` with explicit `__all__` exports: |
| 118 | + |
| 119 | +```python |
| 120 | +from .window import MainWindow |
| 121 | +from .console import Console |
| 122 | +# Import from modules package, not direct file paths |
| 123 | +``` |
| 124 | + |
| 125 | +## PyQt6 Specifics |
| 126 | + |
| 127 | +- UI files created with Qt Designer, loaded via `uic.loadUi()` |
| 128 | +- Icons and assets bundled in `assets/` directory |
| 129 | +- Uses `pathlib` for all file operations (Windows + cross-platform) |
| 130 | +- No custom widgets - uses standard PyQt6 components |
| 131 | + |
| 132 | +## Common Debugging Points |
| 133 | + |
| 134 | +1. **UI Not Loading**: Check that `ui/` directory is accessible from execution path |
| 135 | +2. **XML Parse Errors**: Validate XML has required `duration` attribute and TTS sound elements |
| 136 | +3. **Timing Issues**: Remember all operations are frame-based at 24 FPS |
| 137 | +4. **Speaker Replacements**: Must use exact string matching (case-sensitive) |
| 138 | + |
| 139 | +## Extension Guidelines |
| 140 | + |
| 141 | +- New features → add to `SubtitleProcessor` first, then expose via GUI/console |
| 142 | +- UI changes → modify `.ui` files with Qt Designer, not hand-coding |
| 143 | +- CLI options → extend `Parameters` class argument definitions |
| 144 | +- Keep frame-based timing system for XML compatibility |
0 commit comments