# AV1 Batch Video Transcoder - Project Structure
## Overview
A modular batch AV1 video transcoding system using NVIDIA's av1_nvenc codec (10-bit p010le) with intelligent audio/video processing, subtitle embedding, and optional audio language tagging.
## Recent Changes (Latest Session)
### Removed
- ❌ **Sonarr/Radarr integration** - Removed helper module, cache loading, and config sections (simplified to basic tagging)
- ❌ **Auto-rename functionality** - No longer renames based on Sonarr metadata
- ❌ **Web UI** - Removed `/webui` folder (can be added back if needed)
- ❌ **Rename tool** - Moved to separate `/rename` folder
### Added
- ✅ **Subtitle detection & embedding** - Auto-finds .vtt, .srt, .ass, .ssa, .sub files (including language-prefixed like .en.vtt)
- ✅ **Subtitle cleanup** - Deletes embedded subtitle files after successful encoding
- ✅ **Test mode** (`--test`) - Encodes first file, shows compression ratio, doesn't move files
- ✅ **Optional language tagging** (`--language`) - Only tags audio if explicitly provided (default: no tagging)
- ✅ **Always output MKV** - Changed from using source extension to always outputting .mkv
- ✅ **Improved subtitle matching** - Finds both exact matches (video.vtt) and language-prefixed (video.en.vtt)
### Refactored
- 🔧 **File structure reorganization**: Moved path_manager GUI, rename tool, and cache to separate folders
- 🔧 **Config simplification**: Removed Sonarr/Radarr sections, cleaner general settings
- 🔧 **Suffix handling**: Applied once during encoding, moved directly without re-tagging
- 🔧 **Audio language**: Changed from config-based default to CLI-only optional flag
## Architecture
### Entry Point
- **main.py** - CLI with argparse
- Arguments: `folder`, `--cq`, `--m {cq,bitrate}`, `--r {480,720,1080}`, `--test`, `--language`
- Loads config.xml, initializes logging
- Calls `process_folder()` from process_manager
### Core Modules
#### `core/config_helper.py`
- **`load_config_xml(config_path)`** - Parses XML configuration
- Returns dict with keys:
- `general`: processing_folder, suffix (" - [EHX]"), extensions, reduction_ratio_threshold, subtitles config
- `encode.cq`: CQ values per content type (tv_1080, tv_720, movie_1080, movie_720)
- `encode.fallback`: Bitrate fallback (Phase 2 retry)
- `audio`: Bitrate buckets for stereo/multichannel
- `path_mappings`: Windows ↔ Linux path conversion
#### `core/logger_helper.py`
- Sets up logging to `logs/conversion.log` (INFO+) and console (DEBUG+)
- Separate failure logger for `logs/conversion_failures.log`
- Captures encoding decisions, bitrates, resolutions, timings
#### `core/process_manager.py`
- **`process_folder(folder, cq, transcode_mode, resolution, config, tracker_file, test_mode, audio_language)`**
- Scans folder for video files
- **Per file**: Copy to temp, detect subtitles, analyze streams, encode, move, cleanup
- **Subtitle detection**: Looks for exact match + glob pattern (filename.*.ext)
- **Phase 1 (CQ)**: Try CQ-based encoding, check size threshold
- **Phase 2 (Bitrate)**: Retry failed files with bitrate mode
- **Cleanup**: Delete original + subtitle + temp copies on success
- **`_save_successful_encoding(...)`** - Moves file from temp → original folder
- File already has ` - [EHX]` suffix from temp_output filename
- Deletes original file, subtitle file, and temp copies
- Logs to CSV tracker
#### `core/encode_engine.py`
- **`run_ffmpeg(input_file, output_file, cq, scale_width, scale_height, src_width, src_height, filter_flags, audio_config, method, bitrate_config, subtitle_file, audio_language)`**
- Builds FFmpeg command with av1_nvenc codec (preset p1, pix_fmt p010le)
- Per-stream audio codec/bitrate decisions
- Conditional subtitle input mapping (if subtitle_file provided)
- Optional audio language metadata (only if audio_language not None)
- Returns: (orig_size, out_size, reduction_ratio)
#### `core/audio_handler.py`
- **`get_audio_streams(input_file)`** - Detects all audio streams with bitrate info
- **`choose_audio_bitrate(channels, avg_bitrate, audio_config, is_1080_class)`** - Returns (codec, target_bitrate) tuple
- Stereo 1080p: >192k → encode to 192k, ≤192k → copy
- Stereo 720p: >160k → encode to 160k, ≤160k → copy
- Multichannel: Encode to 384k (low) or 448k (medium)
#### `core/video_handler.py`
- **`get_source_resolution(input_file)`** - ffprobe detection
- **`determine_target_resolution(src_width, src_height, explicit_resolution)`** - Smart scaling
- If >1080p → scale to 1080p
- Else → preserve source
- Override with `--r {480,720,1080}`
## Workflow Example
```bash
python main.py "P:\tv\Supernatural\Season 7" --language eng
```
**Processing:**
1. Scan folder for .mkv/.mp4 files
2. For each file:
- Copy to `processing/Supernatural - S07E01 - Pilot.mkv`
- Look for subtitle: `Supernatural - S07E01 - Pilot.en.vtt` ✓ found
- Detect source: 1920x1080 (1080p) ✓
- Get audio streams: [AAC 2ch @ 192k, AC3 6ch @ 448k]
- Determine CQ: tv_1080 → CQ 28
- Build FFmpeg command:
- Video: av1_nvenc (CQ 28)
- Audio 0: Copy AAC (≤192k already good)
- Audio 1: Re-encode AC3 to AAC 6ch @ 448k
- Subtitles: Input subtitle, map as srt stream, language=eng
- Output: `processing/Supernatural - S07E01 - Pilot - [EHX].mkv`
- FFmpeg runs, outputs ~400MB (original 1.2GB)
- Check size: 400/1200 = 33.3% < 75% ✓ SUCCESS
- Move: `processing/... - [EHX].mkv` → `P:\tv\Supernatural\Season 7/... - [EHX].mkv`
- Cleanup: Delete original + subtitle + temp copy
- Log to CSV
**Result:**
- Original files gone
- New `Supernatural - S07E01 - Pilot - [EHX].mkv` (subtitle embedded, audio tagged with language=eng)
## Configuration
### config.xml Key Sections
```xml
processing
- [EHX]
.mkv,.mp4
0.75
true
.vtt,.srt,.ass,.ssa,.sub
srt
28
32
32
34
```
## File Movements
```
Original:
P:\tv\Show\Episode.mkv (1.2GB)
P:\tv\Show\Episode.en.vtt
During Encoding:
processing/Episode.mkv (temp copy)
processing/Episode - [EHX].mkv (encoding output)
After Success:
P:\tv\Show\Episode - [EHX].mkv (1.2GB → 400MB)
(original .mkv deleted)
(original .en.vtt deleted)
(temp folder cleaned)
```
## Validation Checklist
- ✅ All core modules import correctly
- ✅ Config loads without Sonarr/Radarr references
- ✅ Subtitle detection finds exact matches + language-prefixed files
- ✅ Audio language tagging only applied with --language flag
- ✅ Output always MKV regardless of source format
- ✅ Suffix applied once (in temp output filename)
- ✅ Subtitle files deleted with original files
- ✅ Test mode shows compression ratio and stops
- ✅ Phase 1 (CQ) and Phase 2 (Bitrate) retry logic works
- ✅ CSV tracking logs all conversions