# AV1 Batch Video Transcoder A high-performance batch video transcoding tool using NVIDIA's **AV1 NVENC** or **HEVC NVENC** codec with intelligent audio/subtitle handling, interactive stream selection, and automatic quality optimization. --- ## 📋 Table of Contents 1. [Key Features](#-key-features) 2. [Quick Start](#-quick-start) 3. [Installation](#installation) 4. [Basic Usage](#basic-usage) 5. [Command Reference](#command-reference) 6. [Batch Processing](#batch-processing) 7. [Audio Options](#audio-options) 8. [Undefined Language Replacement](#undefined-language-und-replacement) 9. [Encoder Selection](#encoder-selection) 10. [Configuration](#configuration) 11. [Project Structure](#project-structure) 12. [Encoding Process](#encoding-process) 13. [Troubleshooting](#troubleshooting) --- ## ✨ Key Features ### Video Encoding - **Dual Encoder Support** - NVIDIA AV1 NVENC (8-bit, default) or HEVC NVENC (10-bit) - **Smart Resolution** - Detects source resolution, scales 4K→1080p, preserves lower resolutions - **GPU Acceleration** - Hardware encoding via NVIDIA NVENC (RTX 2060+) - **Two-Phase Mode** - CQ mode first, automatic Bitrate fallback if size threshold exceeded - **Quality Presets** - Per-content-type CQ values (TV/Movies, 720p/1080p) ### Audio Processing - **Smart Audio Processing** - Auto-detects bitrate, AAC for stereo, EAC3 for 5.1 - **Stream Selection** - Keep only best English + Commentary (automatic) or choose manually (interactive) - **Interactive Selection** - View all audio streams and select which ones to keep per file - **Channel Control** - Force specific channel counts (2-channel stereo or 6-channel 5.1 surround) - **Audio Titles** - Rename/tag audio streams with custom titles - **Language Tagging** - Optional language code metadata for audio streams ### Subtitles & Metadata - **Subtitle Embedding** - Auto-detects and embeds subtitles (.vtt, .srt, .ass, .ssa, .sub) - **Language-Prefixed Subtitles** - Finds language-specific files (movie.en.vtt, movie.eng.vtt) - **Automatic Cleanup** - Deletes subtitle files after embedding ### Processing Features - **CSV Tracking** - Detailed conversion logs with compression ratios and media context - **Automatic Cleanup** - Deletes originals + subtitles after successful encoding - **Test Mode** - Encode one file, check compression ratio before batch processing - **Structured Logging** - JSON logs with media type, show name, season/episode context - **File Tagging** - Output files get ` - [EHX]` suffix for easy identification --- ## 🚀 Quick Start ### Requirements - **Python 3.8+** - **FFmpeg** with libfdk-aac support - **NVIDIA GPU** (GeForce RTX 2060+, Quadro, or newer) - **NVIDIA CUDA Toolkit** (for NVENC support) ### Installation ```bash # Clone repository git clone https://github.com/yourusername/conversion_project.git cd conversion_project # Install Python dependencies (if any needed in future) # pip install -r requirements.txt ``` ### Basic Usage ```bash # Encode a TV folder (smart mode with AV1, default) python main.py "P:\tv\Show Name" # Use HEVC encoder (10-bit, better Plex compatibility) python main.py "P:\tv\Show Name" --encoder nvenc # Test single file before batch processing python main.py "P:\tv\Show Name" --test # Force specific quality (CQ 30) python main.py "P:\movies\Movie" --cq 30 # Force bitrate mode python main.py "P:\tv\Show" --m bitrate # Specific resolution python main.py "P:\movies" --r 720 # Tag audio with language python main.py "P:\tv\Show" --language eng # Interactive audio selection python main.py "P:\tv\Show" --filter-audio --interactive ``` --- ## Command Reference ### Encoder Selection ```bash --encoder {av1,nvenc} ``` - `av1` (default): AV1 NVENC, 8-bit, smaller files (~baseline compression) - `nvenc`: HEVC NVENC, 10-bit, larger files (~80-90% of AV1), better compatibility ### Quality & Mode ```bash --cq # Use CQ mode with specific quality (0-51, lower=better) --m {cq,bitrate} # Force encoding mode (default: smart two-phase) ``` ### Resolution ```bash --r {480,720,1080} # Force specific output resolution # Default: scale 4K→1080p, preserve lower ``` ### Audio Options ```bash --filter-audio # Enable automatic audio filtering (keep English + Commentary) --interactive # Interactive mode: show audio streams, user selects which to keep --audio-select "0,1" # Pre-select specific audio streams (indices) --audio-titles "0:English,1:Commentary" # Rename/title audio tracks --audio-channels "0:2,1:6" # Force channel count (2=stereo, 6=5.1 surround) --language eng # Tag audio streams with language code --default-language spa # Set default language for undefined (und) audio tracks --no-replace-und # Disable undefined language tag replacement ``` ### Undefined Language (und) Replacement Automatically replaces undefined (`und`) audio language tags with a configurable default language. Most useful when your video library has audio with undefined language tags that should actually be marked as a specific language. #### Configuration Add to `config.xml` in the `` section: ```xml eng true ``` #### CLI Arguments **`--default-language `** - Override the default language for a single run: ```bash python main.py "P:\movies\Collection" --default-language spa python main.py "P:\tv\Show" --default-language fra ``` **`--no-replace-und`** - Disable undefined language replacement for a single run: ```bash python main.py "P:\movies\Collection" --no-replace-und ``` #### Behavior **Priority Chain** (highest to lowest): 1. `--language eng` (CLI): Tags ALL audio streams as 'eng' 2. `--default-language spa` + detected `und`: Replaces with 'spa' 3. config.xml `default_language: eng` + detected `und`: Replaces with 'eng' 4. `--no-replace-und` flag: Skips all `und` replacement **Key Points:** - Only affects 'und' language tags (existing language tags are preserved) - Works with batch processing (`--paths-file`) - Compatible with TV/movie/anime detection - Works in CQ mode, Bitrate mode, and Smart mode #### Common Language Codes | Code | Language | Code | Language | |------|----------|------|----------| | eng | English | jpn | Japanese | | spa | Spanish | kor | Korean | | fra | French | zho | Chinese (Mandarin) | | deu | German | rus | Russian | | ita | Italian | por | Portuguese | Full list: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes #### Examples **Example 1: Most content is English with `und` tags** ```bash # config.xml already has: eng python main.py "P:\movies" # Result: All 'und' audio streams are tagged as 'eng' ``` **Example 2: Mixed language batch with different defaults** ``` # paths.txt "P:\movies\English Collection" --default-language eng "P:\movies\Spanish Collection" --default-language spa "P:\movies\Mixed" --no-replace-und ``` ```bash python main.py --paths-file paths.txt ``` ### Processing ```bash --test # Test mode: encode first file, show compression ratio, don't move ``` --- ## Batch Processing ### Overview Process multiple folders sequentially with different parameters for each. Perfect for encoding your entire media library with specific settings per movie/show. ### Quick Start ```bash # Simple list format (paths.txt) python main.py --paths-file paths.txt # CSV format with custom parameters (paths_batch.csv) python main.py --paths-file paths_batch.csv ``` ### File Formats #### Format 1: Simple List (paths.txt) One path per line, with optional per-row parameters: ``` P:\movies\Nobody 2 (2025) P:\movies\The French Dispatch (2021) --r 720 P:\movies\Let's Be Cops (2014) --r 720 --cq 28 P:\movies\Akira (1988) --encoder av1 --strip-all-titles ## Batch Processing ### Overview Process multiple folders sequentially with different parameters for each. This replaces the need for manual `.bat` files or shell scripts. Perfect for encoding your entire media library with specific settings per movie/show. ### Quick Start #### Simple List Format (paths.txt) One path per line, with optional per-row parameters: ``` P:\movies\Nobody 2 (2025) P:\movies\The French Dispatch (2021) --r 720 P:\movies\Let's Be Cops (2014) --r 720 --cq 28 P:\movies\Akira (1988) --encoder av1 --strip-all-titles ``` **Usage:** ```bash python main.py --paths-file paths.txt ``` **With base parameters** (applied to all rows unless overridden): ```bash python main.py --paths-file paths.txt --encoder hevc --strip-all-titles ``` #### CSV Format (paths_batch.csv) First column is path, remaining columns are optional parameters: ```csv path,resolution,cq,encoder,notes "P:\movies\Nobody 2 (2025)","--r 1080","--cq 32","--encoder hevc","4K source" "P:\movies\The French Dispatch (2021)","--r 720","--cq 28","--encoder av1","720p source" "P:\movies\Let's Be Cops (2014)","--r 720" "P:\movies\Akira (1988)","","--cq 26" ``` **Usage:** ```bash python main.py --paths-file paths_batch.csv ``` The CSV header row is ignored - use it for your own documentation. ### Supported List Formats #### Simple List (One per line) ``` # Path only (uses base parameters) P:\movies\Movie1 # Path with space-separated parameters P:\movies\Movie2 --r 720 P:\movies\Movie3 --r 720 --cq 28 --encoder av1 # Quoted paths with spaces "P:\movies\Movie with Spaces" --r 720 # Comment out paths with # # P:\movies\Disabled --r 480 ``` #### CSV Format (Recommended for complex setups) First column is always the path. Remaining columns can be any parameters: ```csv path,resolution,quality,encoder,language "P:\movies\Movie1","--r 1080","--cq 32","--encoder hevc","--language eng" "P:\movies\Movie2","--r 720","--cq 28","--encoder av1" "P:\movies\Movie3","--r 720" ``` ### Per-Row Parameter Override Row parameters **override** base CLI parameters for that specific path. **Example:** ```bash # Base command with --strip-all-titles applied to all python main.py --paths-file paths.txt --strip-all-titles ``` With `paths.txt`: ``` P:\movies\Movie1 # Uses --strip-all-titles from base P:\movies\Movie2 --keep-all-titles # OVERRIDES to keep titles, still strips P:\movies\Movie3 --encoder av1 # OVERRIDES encoder to av1 P:\movies\Movie4 --r 720 --cq 28 # OVERRIDES resolution and quality ``` ### All Supported Per-Row Parameters Any CLI parameter can be used in rows: ``` --r {480,720,1080} # Resolution --cq # CQ quality (0-51, lower is better) --m {cq,bitrate} # Encoding mode --encoder {av1,hevc} # Video encoder --audio-channels "0:2,1:6" # Force audio channels --audio-titles "0:English,1:Commentary" # Audio track names --audio-select "0,1" # Pre-select audio streams --language eng # Language tag --filter-audio # Enable audio filtering --strip-all-titles # Remove audio titles --keep-all-titles # Preserve audio titles --unforce-subs # Remove forced subtitle flag --no-encode # Mux only, no encoding --test # Test mode (first file only) --crop-height # Crop to height --color-bit {8,10} # Color bit depth (HEVC only) ``` ### Real-World Examples **Example 1: Movie Library with Varying Quality** `movies.txt`: ``` P:\movies\4K Movies\Movie1 --r 1080 --cq 26 P:\movies\4K Movies\Movie2 --r 1080 --cq 26 P:\movies\720p Movies\Movie3 --r 720 --cq 28 P:\movies\Anime\Anime1 --encoder av1 --cq 26 P:\movies\Anime\Anime2 --encoder av1 --cq 26 --audio-channels "0:2" ``` ```bash python main.py --paths-file movies.txt --encoder hevc --strip-all-titles ``` **Example 2: TV Shows by Season** `tv.csv`: ```csv path,params "P:\tv\Breaking Bad\Season 1","--cq 26" "P:\tv\Breaking Bad\Season 2","--cq 28" "P:\tv\Breaking Bad\Season 3","--cq 28 --r 720" "P:\tv\Game of Thrones\Season 1","--encoder hevc --cq 24" "P:\tv\Game of Thrones\Season 2","--encoder hevc --cq 26" ``` ```bash python main.py --paths-file tv.csv --filter-audio ``` **Example 3: Mixed Content with Language Tags** `archive.txt`: ``` # Movies P:\content\Movies\Action\MovieA --r 1080 --cq 28 --encoder hevc P:\content\Movies\Drama\MovieB --r 1080 --cq 26 --encoder hevc # TV Shows P:\content\TV\Show1\Season1 --cq 28 --filter-audio P:\content\TV\Show2\Season1 --cq 26 --filter-audio --language eng # Anime P:\content\Anime\SeriesA --encoder av1 --cq 24 P:\content\Anime\SeriesB --encoder av1 --cq 26 --audio-channels "0:2" ``` ```bash python main.py --paths-file archive.txt --strip-all-titles ``` ### Batch Processing Output During execution, you'll see detailed progress: ``` ════════════════════════════════════════════════════════════════════════════════ BATCH MODE: Processing paths from paths.txt ════════════════════════════════════════════════════════════════════════════════ ──────────────────────────────────────────────────────────────────────────────── BATCH [1/5]: P:\movies\Movie1 ──────────────────────────────────────────────────────────────────────────────── [... encoding output ...] ✓ [BATCH 1/5] Completed: Movie1 ──────────────────────────────────────────────────────────────────────────────── BATCH [2/5]: P:\movies\Movie2 Parameters: --r 720 ──────────────────────────────────────────────────────────────────────────────── [... encoding output ...] ✓ [BATCH 2/5] Completed: Movie2 [... continues ...] ════════════════════════════════════════════════════════════════════════════════ ✓ BATCH PROCESSING COMPLETE: Processed 5 path(s) ════════════════════════════════════════════════════════════════════════════════ ``` **Key features:** - Each path prefixed with `[BATCH X/Y]` in logs - If a path fails, processing continues to next path - Overall summary shows completion status ### Batch Processing Tips & Best Practices #### 1. Test Before Full Batch Use `--test` flag per-row to verify settings: ``` P:\movies\TestMovie --test --r 720 --cq 28 P:\movies\Movie1 --r 720 --cq 28 P:\movies\Movie2 --r 720 --cq 28 ``` #### 2. Start Simple, Add Complexity ```bash # Phase 1: Just paths python main.py --paths-file paths.txt # Phase 2: Add base parameters python main.py --paths-file paths.txt --encoder hevc # Phase 3: Add per-row customization in the file ``` #### 3. Monitor Progress Check logs in `logs/conversion.log` during batch processing: - Each entry includes `[BATCH X/Y]` prefix - All parameters are logged per file - Search for errors with the batch prefix #### 4. CSV Format Tips - Quote paths with spaces: `"P:\path with spaces"` - Leave empty cells for defaults: `"P:\movies\Movie1","--r 720"` (uses default CQ) - Or combine in one cell: `"P:\movies\Movie1","--r 720 --cq 28"` #### 5. Line Endings - Both Unix (LF) and Windows (CRLF) line endings work - Avoid mixing line endings in the same file #### 6. Encoding Issues If you get encoding errors: - Ensure file is saved as UTF-8 - Use English characters in parameter values - Avoid special characters in paths ### Migration from .bat Files **Old .bat approach:** ```batch python main.py "P:\movies\Movie1" python main.py "P:\movies\Movie2" --r 720 python main.py "P:\movies\Movie3" --r 720 --cq 28 ``` **New --paths-file approach:** ```bash python main.py --paths-file paths.txt ``` With `paths.txt`: ``` P:\movies\Movie1 P:\movies\Movie2 --r 720 P:\movies\Movie3 --r 720 --cq 28 ``` **Benefits:** - Single command to start batch - All parameters visible in one file - Easier to edit and maintain - Better error handling (continues on failure) - Unified logging with batch context --- ## Audio Options ### Three Main Audio Control Methods | Option | Purpose | Format | Example | |--------|---------|--------|---------| | `--audio-select` | Pre-select which streams to keep | Comma-separated indices | `--audio-select "0,1,2"` | | `--audio-titles` | Rename/title tracks | `index:title` pairs | `--audio-titles "0:English,1:Commentary"` | | `--audio-channels` | Set channel count per track | `index:channels` pairs | `--audio-channels "0:2,1:6"` | ### Audio Filtering **Automatic Filtering** (`--filter-audio`): ```bash python main.py "C:\Videos" --filter-audio ``` - Automatically keeps best English audio + all Commentary tracks - Removes other languages - No user interaction **Interactive Filtering** (`--filter-audio --interactive`): ```bash python main.py "C:\Videos" --filter-audio --interactive ``` - Shows all audio streams for each file - User selects which streams to keep - Different selections allowed per file **Stream Display Format**: ``` 🎵 AUDIO STREAM SELECTION ================================================================================ Stream #0: 2ch | Lang: eng | Bitrate: 128kbps Stream #1: 6ch | Lang: eng | Bitrate: 448kbps Stream #2: 2ch | Lang: spa | Bitrate: 128kbps ──────────────────────────────────────────────────────────────────────────── Enter stream numbers to keep (comma-separated, e.g.: 1,2 or just 2) Leave blank to keep all streams ──────────────────────────────────────────────────────────────────────────── ➜ Keep streams: 1,3 ``` ### Audio Channel Control **--audio-channels** allows forcing specific channel configurations: ```bash # Force stereo for all tracks python main.py "C:\Videos" --audio-channels "0:2,1:2" # Keep 5.1 main audio, compress commentary to stereo python main.py "C:\Videos" --audio-channels "0:6,1:2" --audio-titles "0:English 5.1,1:Commentary" ``` **Valid Channels**: 2 (stereo) or 6 (5.1 surround) **Automatic Bitrate Selection**: | Resolution | Stereo (2ch) | 5.1 Surround (6ch) | |-----------|------------|-----------------| | 1080p | 192 kbps | 384 kbps | | 720p | 160 kbps | 320 kbps | ### Audio Filtering Priority When determining output channels for a stream: 1. **User-specified via `--audio-channels`** (highest priority) 2. **Commentary detection** (if titled "Commentary", forces 2-channel) 3. **Auto-detection** (default, based on resolution and source channels) ### Common Audio Scenarios **Scenario 1: TV Show with Commentary** ```bash python main.py "C:\TV" \ --audio-channels "0:2,1:2" \ --audio-titles "0:English,1:Commentary" ``` **Scenario 2: Movie Collection (Multiple Languages)** ```bash python main.py "C:\Movies" \ --audio-select "0,1,2" \ --audio-channels "0:6,1:2,2:2" \ --audio-titles "0:Japanese 5.1,1:English Stereo,2:Spanish Stereo" ``` **Scenario 3: Anime (All Stereo)** ```bash python main.py "C:\Anime" --audio-channels "0:2,1:2,2:2" ``` --- ## Encoder Selection ### Dual Encoder Support **AV1 NVENC (Default)** ```bash python main.py "C:\Videos" --encoder av1 ``` - **Codec**: av1_nvenc - **Preset**: p7 (high quality) - **Bit Depth**: 8-bit - **Pixel Format**: yuv420p - **File Size**: Smallest (~baseline) - **Use Case**: Maximum file size reduction, modern playback devices **HEVC NVENC** ```bash python main.py "C:\Videos" --encoder nvenc ``` - **Codec**: hevc_nvenc - **Preset**: slow (high quality) - **Bit Depth**: 10-bit - **Pixel Format**: yuv420p10le - **File Size**: ~80-90% of AV1 size - **Use Case**: Best quality archival, excellent Plex compatibility ### Quality Comparison | Aspect | HEVC NVENC | AV1 NVENC | |--------|-----------|----------| | **File Size** | ~80-90% of AV1 | Smallest (baseline) | | **Quality** | Excellent | Excellent | | **Preset** | slow (p6) | p7 | | **Bit Depth** | 10-bit | 8-bit | | **Compatibility** | Excellent (Plex) | Good (modern devices) | | **Encoding Speed** | Fast | Fast | --- ## ⚙️ Configuration Edit `config.xml` to customize encoding parameters: ### Video Encoder Settings ```xml ``` ### CQ Quality Per Content Type ```xml 28 32 32 34 ``` ### Audio Bitrate Buckets ```xml ``` ### Bitrate Fallback (Phase 2) ```xml 8000 6000 4000 ``` ### Subtitle Detection ```xml true .vtt,.srt,.ass,.ssa,.sub subrip ``` ### General Settings ```xml .\processing - [EHX] .mkv,.mp4,.avi,.m2ts 0.75 ``` --- ## Project Structure ``` conversion_project/ ├── main.py - CLI entry point for batch transcoding ├── config.xml - Configuration (encoding settings, audio buckets, etc.) │ ├── core/ - Core modules │ ├── config_helper.py - XML configuration loader │ ├── logger_helper.py - Logging setup (JSON structured logs) │ ├── process_manager.py - Main transcoding orchestration │ ├── encode_engine.py - FFmpeg command builder and execution │ ├── audio_handler.py - Audio stream analysis, bitrate decisions, interactive selection │ ├── video_handler.py - Video resolution detection and scaling logic │ └── hardware_helper.py - Hardware detection (GPU/CPU) │ ├── /rename/ - Separate rename utility (rolling_rename.py) ├── /path_manager/ - GUI path management │ ├── gui_path_manager.py │ ├── transcode.bat │ ├── paths.txt │ └── cache/ │ ├── logs/ - Log files and conversion tracker CSV ├── processing/ - Temporary encoding files (cleaned up after move) └── README.md - This file ``` --- ## Encoding Process ### Per-File Workflow For each video file in the target folder: 1. **Detect Subtitles** - Looks for exact match: `Video.vtt`, `Video.srt`, etc. - Also searches for language-prefixed: `Video.en.vtt`, `Video.eng.vtt` 2. **Analyze Source** - Detect resolution (width × height) - Extract audio streams (codec, channels, bitrate, language) - Extract video codec and frame rate 3. **Determine Parameters** - **Target Resolution**: Scale 4K→1080p, preserve lower resolutions (or use `--r` override) - **CQ Value**: Select based on content type and resolution (tv_1080, movie_720, etc.) - **Audio Processing**: - Apply filtering/selection if specified - Choose codec (AAC for stereo, EAC3 for 5.1) - Choose bitrate (depends on resolution and stream quality) 4. **FFmpeg Encode** - **Video**: AV1 NVENC 8-bit yuv420p (or HEVC NVENC 10-bit) - **Audio**: Per-stream decisions (copy if good quality, re-encode if excessive bitrate) - **Subtitles**: Embed as SRT (if found) 5. **Size Validation** - Compare output size vs original size - If output > 75% of original (default threshold), retry with Phase 2 (bitrate mode) 6. **Move File** - Move from temp folder → original location - Add ` - [EHX]` suffix to filename - Delete original file and subtitle file 7. **Logging** - Record to CSV tracker: filename, original size, output size, compression ratio - Structured JSON logging with media context (show name, season, episode) ### Audio Encoding Logic ``` For each audio stream: Stereo audio (2 channels)? ├─ YES + 1080p: │ ├─ If >192kbps → ENCODE to 192 kbps AAC │ └─ If ≤192kbps → COPY (no re-encoding) ├─ YES + 720p: │ ├─ If >160kbps → ENCODE to 160 kbps AAC │ └─ If ≤160kbps → COPY (no re-encoding) │ └─ NO (Multichannel/5.1+): ├─ ENCODE to 384 kbps or 448 kbps EAC3 (depending on resolution) ``` --- ## 📊 Example Output **Input File:** ``` SupernaturalS07E21.mkv (size: 1.5GB, 6-channel AC3 384kbps, 1920x1080) SupernaturalS07E21.en.vtt (subtitle) ``` **Processing:** ``` Detected: 1920x1080 (1080p) → TV episode CQ 28 Audio: 6ch AC3 384kbps (needs re-encoding for 5.1) Subtitle: Detected SupernaturalS07E21.en.vtt ``` **Output File:** ``` SupernaturalS07E21 - [EHX].mkv (size: 420MB, EAC3 384kbps, subtitle embedded) Compression: 1500MB → 420MB (72% reduction) ``` --- ## Troubleshooting ### Common Issues **"FFmpeg not found"** - Ensure FFmpeg is installed and in your system PATH - Test with: `ffmpeg -version` **"GPU out of memory"** - NVIDIA GPU is full, close other GPU applications - Or reduce resolution with `--r 720` **"Subtitle not embedding"** - Ensure subtitle file is in same folder as video - Check subtitle extension is in config.xml (vtt, srt, ass, etc.) - Verify filename matches exactly (e.g., `Video.en.vtt`) **"No audio streams detected"** - Run `ffprobe input.mkv` to verify audio streams exist - Audio may be embedded as data track, not audio track **"CUDA Kernel Error" during encoding** - GPU driver is outdated, update NVIDIA drivers - GPU may be overheating, check temperature **"Output file larger than original"** - Phase 1 (CQ mode) exceeded size threshold - Phase 2 (bitrate mode) will retry automatically - Or manually increase CQ value (lower quality) in config.xml --- ## Advanced Features ### Test Mode Encodes first file only without moving it: ```bash python main.py "P:\tv\Show" --test ``` **Use Case**: Test CQ values, check quality before batch processing entire library. ### Language Tagging Tags audio streams with language metadata (only if specified): ```bash python main.py "P:\tv\Show" --language eng ``` Without the flag, original audio metadata is preserved. ### Resolution Override Force specific output resolution regardless of source: ```bash python main.py "P:\movies" --r 720 # Force 720p python main.py "P:\tv" --r 1080 # Force 1080p ``` ### CSV Conversion Tracking All conversions logged to CSV file with: - Filename - Original size - Output size - Compression ratio - Encoding method (CQ/Bitrate) - Duration - Timestamp --- ## Logging The system uses structured JSON logging with media context: ### Log Fields - **timestamp**: When the conversion occurred - **level**: INFO, WARNING, ERROR - **message**: Human-readable conversion status - **video_filename**: Original filename - **media_type**: "tv", "anime", "movie", or "other" - **show_name**: Extracted from path (e.g., "Breaking Bad") - **season**: TV/anime season number (optional) - **episode**: TV/anime episode number (optional) - **method**: "CQ" or "Bitrate" - **original_size_mb**: Input file size - **output_size_mb**: Output file size - **reduction_pct**: Compression percentage ### Log Files - **logs/conversion.log**: Full structured JSON logs (INFO level and above) - **logs/conversion_failures.log**: Error and failure logs only - **conversion_tracker.csv**: Human-readable conversion summary --- ## Recent Changes ### Latest Updates ✅ **Dual Encoder Support** - Switch between AV1 and HEVC with `--encoder` flag ✅ **Interactive Audio Selection** - Manually choose which audio streams to keep ✅ **Audio Channel Control** - Force specific channel counts (2-ch stereo or 6-ch 5.1) ✅ **Audio Stream Titles** - Rename/tag individual audio tracks ✅ **Structured JSON Logging** - Media context in all logs (show name, season, episode) ✅ **Subtitle Embedding** - Auto-detect and embed subtitles with language prefixes ✅ **Test Mode** - Encode first file to verify settings before batch processing ### Removed Features ❌ Sonarr/Radarr integration (simplified for reliability) ❌ Auto-rename based on external metadata ❌ Web UI (can be added back if needed) --- ## 📊 Example Output **Input:** ``` Show.S01E01.mkv (1.5GB) Show.S01E01.en.vtt (subtitle) ``` **Output:** ``` Show.S01E01 - [EHX].mkv (450MB, subtitle embedded, audio tagged) ``` **Compression:** 1.5GB → 450MB (30% ratio, 70% reduction) ## 🔧 Encoding Specs | Setting | Value | |---------|-------| | Video Codec | AV1 (av1_nvenc) | | Bit Depth | 8-bit (yuv420p) | | GPU Preset | p1 (high quality) | | Audio Codec | AAC | | Audio Mode | Smart (copy or re-encode) | | Container | MKV | | Subtitles | Embedded SRT | ## 🎯 Workflow 1. **Scan** folder for video files 2. **Detect** subtitles, audio streams, resolution 3. **Encode** with AV1 codec (Phase 1: CQ) 4. **Check** size threshold (default 75%) 5. **Retry** with Bitrate mode if needed (Phase 2) 6. **Move** encoded file to original location 7. **Cleanup** original + subtitles + temp files 8. **Log** results to CSV tracker ## 📋 Requirements - Windows 10/11 or Linux - NVIDIA GPU with NVENC support - NVIDIA CUDA Toolkit 11.0+ - FFmpeg compiled with av1_nvenc support - Python 3.8+ ## 🛠️ Troubleshooting **Files not moving?** - Check `reduction_ratio_threshold` in config.xml (default 0.75) - Run with `--test` to see compression ratio **Subtitles not embedding?** - Verify filename: `video.en.vtt` or `video.vtt` - Check config.xml `true` **Wrong audio quality?** - Adjust CQ values in config.xml per content type - Use `--cq` override: `python main.py folder --cq 30` **"FFmpeg not found"** - Ensure FFmpeg is installed and in your system PATH - Test with: `ffmpeg -version` **"GPU out of memory"** - NVIDIA GPU is full, close other GPU applications - Or reduce resolution with `--r 720` **"No audio streams detected"** - Run `ffprobe input.mkv` to verify audio streams exist - Audio may be embedded as data track, not audio track **"CUDA Kernel Error" during encoding** - GPU driver is outdated, update NVIDIA drivers - GPU may be overheating, check temperature **"Output file larger than original"** - Phase 1 (CQ mode) exceeded size threshold - Phase 2 (bitrate mode) will retry automatically - Or manually increase CQ value (lower quality) in config.xml ## 📄 License MIT