diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
deleted file mode 100644
index 447c599..0000000
--- a/ARCHITECTURE.md
+++ /dev/null
@@ -1,422 +0,0 @@
-# Interactive Audio Stream Selection - Architecture Diagram
-
-## System Architecture
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ main.py │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ ArgumentParser │ │
-│ │ --filter-audio (enables audio filtering) │ │
-│ │ --interactive (enables interactive mode) ← NEW │ │
-│ │ --cq, --r, --m, --language, --test (existing) │ │
-│ └──────────────────────────────────────────────────────────┘ │
-│ ↓ │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ normalize_input_path() → folder path │ │
-│ └──────────────────────────────────────────────────────────┘ │
-│ ↓ │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ process_folder( │ │
-│ │ filter_audio=True/False, │ │
-│ │ interactive_audio=True/False ← NEW │ │
-│ │ ) │ │
-│ └──────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ core/process_manager.py │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ process_folder(folder, ..., filter_audio, interactive) │ │
-│ │ ↑ NEW param │ │
-│ └──────────────────────────────────────────────────────────┘ │
-│ ↓ │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ For each video file: │ │
-│ │ 1. Get source resolution & target resolution │ │
-│ │ 2. Create audio_filter_config dict: │ │
-│ │ { │ │
-│ │ "enabled": filter_audio, │ │
-│ │ "interactive": interactive_audio ← NEW FIELD │ │
-│ │ } │ │
-│ │ 3. Call run_ffmpeg() with audio_filter_config │ │
-│ └──────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ core/encode_engine.py │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ run_ffmpeg( │ │
-│ │ input_file, output_file, ..., │ │
-│ │ audio_filter_config={enabled, interactive} │ │
-│ │ ) │ │
-│ └──────────────────────────────────────────────────────────┘ │
-│ ↓ │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ 1. streams = get_audio_streams(input_file) │ │
-│ │ └─ Returns: [(index, ch, br, lang, meta), ...] │ │
-│ │ │ │
-│ │ 2. if audio_filter_config.get("enabled"): │ │
-│ │ ├─ if audio_filter_config.get("interactive"): │ │
-│ │ │ └─ Call: prompt_user_audio_selection(streams) ← ◆ │ │
-│ │ │ [SHOWS PROMPT TO USER] │ │
-│ │ │ └─ Returns: filtered_streams │ │
-│ │ │ │ │
-│ │ └─ else: │ │
-│ │ └─ Call: filter_audio_streams(input_file, streams) │ │
-│ │ (Automatic: keep best English + Commentary) │ │
-│ │ └─ Returns: filtered_streams │ │
-│ │ │ │
-│ │ 3. For each stream in filtered_streams: │ │
-│ │ ├─ choose_audio_bitrate() (codec selection) │ │
-│ │ └─ Build FFmpeg codec params (-c:a, -b:a, etc.) │ │
-│ │ │ │
-│ │ 4. subprocess.run(ffmpeg_cmd) │ │
-│ └──────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ core/audio_handler.py │
-│ ┌──────────────────────────────────────────────────────────┐ │
-│ │ def prompt_user_audio_selection(streams) ← NEW FUNCTION │ │
-│ │ ◆ Interactive User Prompt ◆ │ │
-│ │ │ │
-│ │ Display: │ │
-│ │ ┌──────────────────────────────────────────────┐ │ │
-│ │ │ 🎵 AUDIO STREAM SELECTION │ │ │
-│ │ │ │ │ │
-│ │ │ Stream #0: 2ch | Lang: eng | Bitrate: 128kbps │ │
-│ │ │ Stream #1: 6ch | Lang: eng | Bitrate: 448kbps │ │
-│ │ │ Stream #2: 2ch | Lang: spa | Bitrate: 128kbps │ │
-│ │ │ Stream #3: 2ch | Lang: comment | Bitrate: 64kbps │ │
-│ │ │ │ │ │
-│ │ │ Keep streams: 1,3 │ │ │
-│ │ │ │ │ │
-│ │ │ ✅ Keeping 2 stream(s), removing 2 stream(s) │ │
-│ │ └──────────────────────────────────────────────┘ │ │
-│ │ │ │
-│ │ Process: │ │
-│ │ 1. Check if streams empty/single → return as-is │ │
-│ │ 2. Display all streams with formatting │ │
-│ │ 3. Prompt user for comma-separated indices │ │
-│ │ 4. Parse and validate input │ │
-│ │ 5. Filter streams to selected only │ │
-│ │ 6. Log selections & removed streams │ │
-│ │ 7. Return filtered_streams │ │
-│ │ │ │
-│ │ Error Handling: │ │
-│ │ • Invalid input → Keep all (log warning) │ │
-│ │ • No selections → Keep all (log warning) │ │
-│ │ • Empty input → Keep all (user confirmed) │ │
-│ └──────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-## Data Flow Example
-
-### User Command
-```bash
-python main.py "C:\Videos" --filter-audio --interactive
-```
-
-### Data Transformation
-
-```
-Step 1: ArgumentParser
-─────────────────────
-Input Args:
- folder = "C:\Videos"
- filter_audio = True
- interactive_audio = True
-
-Output: args object
-
-────────────────────────────────────────────────────────
-
-Step 2: main() → process_folder()
-───────────────────────────────────
-Input:
- folder, filter_audio=True, interactive_audio=True
-
-Output: Called with both flags
-
-────────────────────────────────────────────────────────
-
-Step 3: process_folder() → Builds audio_filter_config
-──────────────────────────────────────────────────────
-Input:
- filter_audio=True
- interactive_audio=True
-
-Logic:
- if filter_audio is not None:
- audio_filter_config = {
- "enabled": True,
- "interactive": True ← NEW
- }
-
-Output: audio_filter_config dict
-
-────────────────────────────────────────────────────────
-
-Step 4: process_folder() → run_ffmpeg()
-─────────────────────────────────────────
-Input:
- input_file = "movie.mkv"
- audio_filter_config = {"enabled": True, "interactive": True}
-
-Output: Called with config
-
-────────────────────────────────────────────────────────
-
-Step 5: run_ffmpeg() → Audio Stream Detection
-──────────────────────────────────────────────
-Input:
- input_file = "movie.mkv"
-
-Output:
- streams = [
- (0, 2, 128, "eng", 0), # Stream #0: 2ch English 128kbps
- (1, 6, 448, "eng", 0), # Stream #1: 6ch English 448kbps
- (2, 2, 128, "spa", 0), # Stream #2: 2ch Spanish 128kbps
- (3, 2, 64, "und", 0) # Stream #3: 2ch Undefined 64kbps
- ]
-
-────────────────────────────────────────────────────────
-
-Step 6: Audio Filtering Decision
-────────────────────────────────
-Input:
- audio_filter_config = {"enabled": True, "interactive": True}
- streams = [4 streams above]
-
-Logic:
- if audio_filter_config.get("enabled"): ✓ True
- if audio_filter_config.get("interactive"): ✓ True
- → Call prompt_user_audio_selection() ← INTERACTIVE PATH
-
-Output: User prompt shown to console
-
-────────────────────────────────────────────────────────
-
-Step 7: prompt_user_audio_selection() → User Input
-──────────────────────────────────────────────────────
-Input:
- streams = [4 streams]
-
-Display:
- 🎵 AUDIO STREAM SELECTION
- ════════════════════════════════════════════════════
- Stream #0: 2ch | Lang: eng | Bitrate: 128kbps
- Stream #1: 6ch | Lang: eng | Bitrate: 448kbps
- Stream #2: 2ch | Lang: spa | Bitrate: 128kbps
- Stream #3: 2ch | Lang: undefined | Bitrate: 64kbps
-
- Keep streams: ← WAIT FOR USER INPUT
-
-User Input:
- "1,3"
-
-Parse:
- selected_indices = {1, 3}
-
-Filter:
- filtered = [
- (1, 6, 448, "eng", 0), ✓ Keep
- (3, 2, 64, "und", 0) ✓ Keep
- ]
-
-Output:
- ✅ Keeping 2 stream(s), removing 2 stream(s)
-
- Return: filtered streams
-
-────────────────────────────────────────────────────────
-
-Step 8: Back to run_ffmpeg() → Codec Selection
-──────────────────────────────────────────────
-Input:
- streams = [
- (1, 6, 448, "eng", 0),
- (3, 2, 64, "und", 0)
- ]
-
-Process each stream:
- Stream 1: 6ch → choose_audio_bitrate() → ("eac3", 384000)
- Stream 3: 2ch → choose_audio_bitrate() → ("aac", 160000)
-
-Output:
- FFmpeg codec params:
- -c:a:1 eac3 -b:a:1 384k -ac:1 6 -channel_layout:1 5.1
- -c:a:3 aac -b:a:3 160k -ac:3 2 -channel_layout:3 stereo
-
-────────────────────────────────────────────────────────
-
-Step 9: FFmpeg Encoding
-───────────────────────
-Input:
- ffmpeg -i movie.mkv \
- -vf scale=... \
- -c:v av1_nvenc \
- -c:a:1 eac3 -b:a:1 384k ... \
- -c:a:3 aac -b:a:3 160k ... \
- output.mkv
-
-Process:
- FFmpeg encodes video and audio streams
- Only streams 1 and 3 included (streams 0 and 2 excluded)
-
-Output:
- output.mkv (with only selected audio tracks)
-```
-
-## State Diagram
-
-```
- ┌─────────────────────────────────┐
- │ User Runs Script │
- │ --filter-audio --interactive │
- └──────────────┬──────────────────┘
- │
- ▼
- ┌─────────────────────────────────┐
- │ Parse Arguments │
- │ interactive_audio = True │
- └──────────────┬──────────────────┘
- │
- ▼
- ┌─────────────────────────────────┐
- │ process_folder() │
- │ Build audio_filter_config │
- │ {enabled: T, interactive: T} │
- └──────────────┬──────────────────┘
- │
- ┌────────────┴────────────┐
- │ │
- ▼ ▼
- For each file Detect audio streams
- ┌──────────────┐ get_audio_streams()
- │ run_ffmpeg() │ └─ Returns 4 streams
- └──────┬───────┘
- │
- ▼
- ┌──────────────────────────┐
- │ Check filter enabled? │
- │ audio_filter_config │
- └──────┬─────────────┬─────┘
- │ No │ Yes
- │ ▼
- │ ┌─────────────────────┐
- │ │ Check interactive? │
- │ └────┬────────────┬───┘
- │ │ No │ Yes
- │ │ ▼
- │ │ ┌───────────────────┐
- │ │ │ INTERACTIVE PROMPT│
- │ │ │ Show streams │
- │ │ │ Get user input │
- │ │ │ Filter streams │
- │ │ └─────────┬─────────┘
- │ │ │
- │ ▼ │
- │ ┌──────────────────┐ │
- │ │ Automatic Filter │ │
- │ │ (Best English + │ │
- │ │ Commentary) │ │
- │ └─────────┬────────┘ │
- │ │ │
- └────────────────┴───────────┘
- │
- ▼
- ┌────────────────────────────────┐
- │ Apply Codec Selection │
- │ (for selected streams only) │
- │ choose_audio_bitrate() │
- └────────────┬───────────────────┘
- │
- ▼
- ┌────────────────────────────────┐
- │ Build FFmpeg Command │
- │ (with selected audio streams) │
- └────────────┬───────────────────┘
- │
- ▼
- ┌────────────────────────────────┐
- │ Run FFmpeg Encoding │
- │ subprocess.run(cmd) │
- └────────────┬───────────────────┘
- │
- ▼
- ┌────────────────────────────────┐
- │ Success/Failure Handling │
- │ Log Results │
- └────────────┬───────────────────┘
- │
- ┌────────────┴─────────┐
- │ │
- Next file? Process Complete
-```
-
-## Component Interaction
-
-```
-┌─────────────┐
-│ main.py │
-└──────┬──────┘
- │ calls with (filter_audio, interactive_audio)
- │
- ▼
-┌──────────────────────┐
-│ process_manager.py │
-├──────────────────────┤
-│ • Build config │ ◄─── Set "interactive" field
-│ • For each file: │ in audio_filter_config
-│ └─ run_ffmpeg() │
-└──────┬───────────────┘
- │ passes audio_filter_config
- │
- ▼
-┌──────────────────────┐
-│ encode_engine.py │
-├──────────────────────┤
-│ • Check "enabled" │ ◄─── Decide which
-│ • Check "interactive"│ filtering method
-│ • Route to: │ to use
-│ ├─ interactive path│
-│ └─ automatic path │
-└──────┬───────────────┘
- │ passes streams
- │
- ▼
-┌──────────────────────┐
-│ audio_handler.py │
-├──────────────────────┤
-│ • Interactive: │
-│ prompt_user_...() │◄──── NEW FUNCTION
-│ └─ Show & filter │ Shows prompt
-│ │ Gets user input
-│ • Automatic: │ Returns filtered
-│ filter_audio_...() │
-│ └─ Logic filter │
-└──────────────────────┘
- │ returns filtered streams
- │
- ▼
-┌──────────────────────┐
-│ encode_engine.py │
-├──────────────────────┤
-│ • Codec selection │
-│ • Build FFmpeg cmd │
-│ • Run encoding │
-└──────────────────────┘
-```
-
----
-
-This architecture ensures clean separation of concerns:
-- **main.py**: CLI interface
-- **process_manager.py**: Orchestration & config building
-- **encode_engine.py**: FFmpeg command building & execution
-- **audio_handler.py**: Audio detection & stream filtering
-
-The interactive prompt is cleanly isolated in `audio_handler.py` and only called when needed.
diff --git a/ENCODER_SWITCH.md b/ENCODER_SWITCH.md
deleted file mode 100644
index e0ad594..0000000
--- a/ENCODER_SWITCH.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Dual Encoder Support - Implementation Complete ✅
-
-## Features Added
-
-The transcoder now supports switching between two video encoders via the `--encoder` CLI option:
-
-### 1. **HEVC NVENC 10-bit** (Default)
-- **Command**: `--encoder nvenc` or default (no flag needed)
-- **Codec**: `hevc_nvenc`
-- **Preset**: `slow` (high quality)
-- **Bit Depth**: 10-bit
-- **Pixel Format**: `yuv420p10le`
-- **Use Case**: Best quality archival format, suitable for Plex compatibility
-
-### 2. **AV1 NVENC 8-bit**
-- **Command**: `--encoder av1`
-- **Codec**: `av1_nvenc`
-- **Preset**: `p7` (high quality)
-- **Bit Depth**: 8-bit
-- **Pixel Format**: `yuv420p`
-- **Use Case**: Maximum file size reduction, modern playback devices
-
-## Usage Examples
-
-```bash
-# Default to HEVC NVENC 10-bit with smart resolution scaling
-python main.py "C:\Videos\Movies"
-
-# Force AV1 NVENC 8-bit encoding
-python main.py "C:\Videos\TV" --encoder av1
-
-# AV1 with explicit resolution
-python main.py "C:\Videos\Anime" --encoder av1 --r 1080
-
-# AV1 with CQ mode at specific quality
-python main.py "C:\Videos\Low-Res" --encoder av1 --cq 28
-
-# AV1 with bitrate mode
-python main.py "C:\Videos\Movies" --encoder av1 --m bitrate
-
-# HEVC (explicit, though it's the default)
-python main.py "C:\Videos\TV" --encoder nvenc --cq 26
-```
-
-## Configuration
-
-Encoder settings are stored in `config.xml`:
-
-```xml
-
-
-
-
-```
-
-The `default="nvenc"` attribute can be changed, but CLI `--encoder` flag always takes precedence.
-
-## Files Modified
-
-1. **config.xml** - Added `` section with both encoder configurations
-2. **main.py** - Added `--encoder` argument, defaults to "nvenc"
-3. **encode_engine.py** - Updated `run_ffmpeg()` to:
- - Accept `encoder` parameter
- - Dynamically set encoder codec, preset, bit depth, and pixel format
- - Display encoder details in logging output
-4. **process_manager.py** - Updated to:
- - Accept and pass `encoder` parameter through processing pipeline
- - Updated both Phase 1 (initial encode) and Phase 2 (bitrate retry) encode calls
-
-## Quality Notes
-
-| 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 |
-
-Both encoders use NVIDIA GPU acceleration (NVENC) for fast encoding.
diff --git a/IMPLEMENTATION_COMPLETE.md b/IMPLEMENTATION_COMPLETE.md
deleted file mode 100644
index 89c83bc..0000000
--- a/IMPLEMENTATION_COMPLETE.md
+++ /dev/null
@@ -1,280 +0,0 @@
-# Interactive Audio Stream Selection - Complete Implementation
-
-## Overview
-✅ **COMPLETE** - Interactive audio stream selection feature has been successfully implemented.
-
-Users can now view all available audio streams in each video file and select which ones to keep for encoding, providing fine-grained control over audio track inclusion.
-
-## Features Implemented
-
-### 1. Stream Display ✅
-- Shows all audio streams with human-readable format
-- Displays: Stream number, channel count, language code, bitrate
-- Clear visual separation and organized layout
-- Example: `Stream #0: 2ch | Lang: eng | Bitrate: 128kbps`
-
-### 2. User Input ✅
-- Accepts comma-separated stream indices: `0,1,3`
-- Accepts single stream: `1`
-- Accepts blank input (keep all streams)
-- Input validation with helpful error messages
-- Optional spaces in comma-separated list: `0, 1, 3`
-
-### 3. Filtering ✅
-- Removes non-selected streams from encoding
-- Preserves original stream indices for FFmpeg mapping
-- Logs all selections and removals
-- Falls back to keeping all streams on invalid input
-
-### 4. CLI Integration ✅
-- New flag: `--interactive` (boolean)
-- Works with `--filter-audio` flag
-- Can be used independently (auto-enables filtering)
-- Integrated into argument parser with help text
-
-### 5. Processing Pipeline ✅
-- Called from `run_ffmpeg()` in encode_engine.py
-- Executed after stream detection
-- Executed before codec selection
-- Per-file prompting (allows different selections per video)
-
-### 6. Logging ✅
-- Logs user selections: `User selected X audio stream(s): [0, 1, 3]`
-- Logs removed streams: `Removed X audio stream(s): [2]`
-- Logs invalid input attempts
-- Integrated with project's logging system
-
-## File Changes Summary
-
-### main.py
-**Added**:
-- `--interactive` argument to argparse
-- Pass `args.interactive_audio` to `process_folder()`
-
-**Lines Changed**: 2
-
-### core/process_manager.py
-**Added**:
-- `interactive_audio: bool = False` parameter to function signature
-- Logic to set `audio_filter_config["interactive"]` based on CLI args
-- Auto-enable filtering if `--interactive` used without `--filter-audio`
-
-**Lines Changed**: ~5
-
-### core/encode_engine.py
-**Added**:
-- Import `prompt_user_audio_selection`
-- Check for `audio_filter_config.get("interactive", False)`
-- Route to interactive or automatic filtering accordingly
-
-**Lines Changed**: ~5
-
-### core/audio_handler.py
-**Added**:
-- `prompt_user_audio_selection()` function (64 lines)
-- Comprehensive docstring
-- User-friendly output formatting
-- Input validation and error handling
-- Logging integration
-
-**Lines Changed**: +64 (new function)
-
-## Code Structure
-
-### Function: `prompt_user_audio_selection(streams: list) -> list`
-**Location**: `core/audio_handler.py` (line 297)
-
-**Parameters**:
-- `streams`: List of (index, channels, bitrate, language, metadata) tuples
-
-**Returns**:
-- Filtered list containing only user-selected streams
-
-**Key Features**:
-1. Early return if 0-1 streams (no selection needed)
-2. Display header with visual formatting
-3. Show each stream with index, channels, language, bitrate
-4. Prompt for user input with examples
-5. Parse comma-separated input
-6. Validate stream indices
-7. Handle edge cases (empty input, invalid input)
-8. Log results to project logger
-9. Return filtered streams ready for encoding
-
-**Error Handling**:
-- ValueError on unparseable input → keep all
-- No valid selections → keep all with warning
-- Empty input → keep all (user confirmed)
-
-## Execution Flow
-
-```
-User runs:
-$ python main.py "C:\Videos" --filter-audio --interactive
-
-↓
-
-main.py parses arguments
- - filter_audio = True (from --filter-audio)
- - interactive_audio = True (from --interactive)
-
-↓
-
-process_folder() called with both flags
-
-↓
-
-For each video file:
- └─ run_ffmpeg() called
- └─ get_audio_streams() detects streams
- └─ Check audio_filter_config.enabled
- └─ True: Apply filtering
- └─ Check audio_filter_config.interactive
- └─ True: Call prompt_user_audio_selection()
- └─ [INTERACTIVE PROMPT APPEARS]
- └─ User sees streams and selects
- └─ Returns filtered stream list
- └─ False: Call filter_audio_streams()
- └─ Automatic filtering (keep best English + Commentary)
- └─ Process selected streams for encoding
-```
-
-## Usage Examples
-
-### Basic Interactive Mode
-```bash
-python main.py "C:\Videos\Movies" --filter-audio --interactive
-```
-
-### Combined with Other Options
-```bash
-python main.py "C:\Videos\TV" --filter-audio --interactive --cq 28 --r 1080 --language eng
-```
-
-### Interactive Without Explicit --filter-audio
-```bash
-python main.py "C:\Videos\Anime" --interactive
-```
-(Filtering is auto-enabled with interactive mode)
-
-## Testing Scenarios
-
-### Scenario 1: Multiple Audio Languages
-**Input**: Video with English (stereo), English (5.1), Spanish, Commentary
-**Expected**: Prompt shows 4 streams, user can select any combination
-
-### Scenario 2: Invalid Selection
-**Input**: User types "abc" or non-existent stream number
-**Expected**: Tool logs warning, keeps all streams, continues
-
-### Scenario 3: Single Audio Stream
-**Input**: Video with only one audio track
-**Expected**: Function returns early, no prompt shown
-
-### Scenario 4: Empty Input
-**Input**: User presses Enter without typing
-**Expected**: All streams kept, confirmation message shown
-
-## Backward Compatibility
-
-✅ **Fully Backward Compatible**
-- Existing `--filter-audio` behavior unchanged
-- New feature is opt-in via `--interactive` flag
-- Default behavior (no interactive) preserved
-- No changes to config.xml schema required
-- All existing scripts/automation continues to work
-
-## Integration Points
-
-### With Audio Language Tagging
-- `--language eng --filter-audio --interactive` works together
-- User selects streams, then language metadata applied to all
-
-### With Resolution/CQ Options
-- `--filter-audio --interactive --cq 28 --r 1080` fully compatible
-- Interactive selection happens first, encoding follows
-
-### With Test Mode
-- `--filter-audio --interactive --test` shows interactive prompt on first file
-- Useful for testing selections before batch encoding
-
-## Performance Impact
-
-✅ **Minimal Impact**
-- Interactive prompt only appears when user explicitly requests it
-- No performance overhead when `--interactive` not used
-- Per-file prompt adds negligible time (user wait for input)
-- No change to FFmpeg encoding performance
-
-## Documentation Provided
-
-1. **INTERACTIVE_AUDIO.md** - User guide with examples
-2. **IMPLEMENTATION_NOTES.md** - Technical implementation details
-3. **QUICK_REFERENCE.md** - Quick reference guide and FAQ
-4. This summary document
-
-## Completion Checklist
-
-✅ Function implementation (prompt_user_audio_selection)
-✅ CLI argument (--interactive)
-✅ Integration with process_manager
-✅ Integration with encode_engine
-✅ Input validation
-✅ Error handling
-✅ Logging integration
-✅ Backward compatibility
-✅ Documentation
-✅ Syntax validation
-✅ Code review
-
-## Example Output
-
-When user runs with `--filter-audio --interactive`:
-
-```
-================================================================================
-🎵 AUDIO STREAM SELECTION
-================================================================================
-
-Stream #0: 2ch | Lang: eng | Bitrate: 128kbps
-
-Stream #1: 6ch | Lang: eng | Bitrate: 448kbps
-
-Stream #2: 2ch | Lang: spa | Bitrate: 128kbps
-
-Stream #3: 2ch | Lang: comment | Bitrate: 64kbps
-
-────────────────────────────────────────────────────────────────────────────
-Enter stream numbers to keep (comma-separated, e.g.: 1,2 or just 2)
-Leave blank to keep all streams
-────────────────────────────────────────────────────────────────────────────
-➜ Keep streams: 1,3
-✅ Keeping 2 stream(s), removing 2 stream(s)
-
-🎬 Running CQ encode: output.mkv
-...
-```
-
-## Next Steps (Optional Enhancements)
-
-Future improvements could include:
-- [ ] Preset buttons for common selections (e.g., "Best Audio", "English Only", "All")
-- [ ] Auto-numbering display for clarity
-- [ ] Arrow key selection interface (more interactive)
-- [ ] Save/load selection templates for batch consistency
-- [ ] GUI interface for stream selection
-- [ ] Default selection from config for silent/batch operation
-
----
-
-## Summary
-
-The interactive audio stream selection feature is **complete and ready for use**. Users can now:
-
-1. ✅ See all available audio streams with details
-2. ✅ Choose which streams to keep for encoding
-3. ✅ Get immediate confirmation of their selection
-4. ✅ Have per-file control in batch operations
-5. ✅ Maintain automatic fallback if input is invalid
-
-The implementation is clean, well-documented, backward-compatible, and fully integrated into the existing codebase.
diff --git a/IMPLEMENTATION_NOTES.md b/IMPLEMENTATION_NOTES.md
deleted file mode 100644
index ec6bfe4..0000000
--- a/IMPLEMENTATION_NOTES.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# Interactive Audio Stream Selection - Implementation Summary
-
-## Changes Made
-
-### 1. New Function: `prompt_user_audio_selection()` in audio_handler.py
-- **Purpose**: Display audio streams and prompt user for selection
-- **Input**: List of streams with (index, channels, bitrate, language, metadata)
-- **Output**: Filtered list containing only user-selected streams
-- **Features**:
- - Displays stream info: `Stream #X: YYch | Lang: YYY | Bitrate: XYZkbps`
- - Accepts comma-separated input: `1,2,3` or `1` or empty (keep all)
- - Validates input and logs selections
- - Falls back to keeping all streams on invalid input
-
-### 2. Updated: `run_ffmpeg()` in encode_engine.py
-- Now checks `audio_filter_config.get("interactive", False)`
-- Routes to interactive prompt if `interactive=True`
-- Routes to automatic filtering if `interactive=False`
-- Both modes filter streams before codec selection
-
-### 3. Updated: `process_folder()` in process_manager.py
-- New parameter: `interactive_audio: bool = False`
-- Builds audio_filter_config with both `enabled` and `interactive` fields
-- If `--interactive` used without `--filter-audio`, enables both automatically
-
-### 4. Updated: main.py
-- New CLI argument: `--interactive`
-- Action: `store_true` (binary flag)
-- Passed through to `process_folder()`
-- Help text: "Interactive mode: show audio streams and let user select which to keep (requires --filter-audio)"
-
-## Usage Examples
-
-### Example 1: Automatic Filtering (Existing)
-```bash
-python main.py "C:\Videos" --filter-audio
-```
-- Automatically keeps best English + Commentary
-- No user interaction
-
-### Example 2: Interactive Selection (New)
-```bash
-python main.py "C:\Videos" --filter-audio --interactive
-```
-- Shows each file's audio streams
-- User picks which streams to keep
-- Different selections per file allowed
-
-### Example 3: Interactive Without --filter-audio
-```bash
-python main.py "C:\Videos" --interactive
-```
-- Same as Example 2 (enables filtering automatically)
-- More intuitive UX
-
-## Stream Display Format
-
-When interactive mode runs, user sees:
-```
-================================================================================
-🎵 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:
-```
-
-## Logging Output
-
-When user selects streams:
-```
-✅ Keeping 2 stream(s), removing 1 stream(s)
-
-User selected 2 audio stream(s): [1, 2]
-Removed 1 audio stream(s): [0]
-```
-
-## Audio Filter Config Structure
-
-**Old (Automatic only)**:
-```python
-{
- "enabled": True/False
-}
-```
-
-**New (With Interactive)**:
-```python
-{
- "enabled": True/False,
- "interactive": True/False
-}
-```
-
-## Flow Diagram
-
-```
-main.py
- └─ parse args (--filter-audio, --interactive)
- └─ process_folder()
- └─ for each file:
- └─ run_ffmpeg()
- └─ get_audio_streams()
- └─ if audio_filter_config.enabled:
- ├─ if audio_filter_config.interactive:
- │ └─ prompt_user_audio_selection() ← NEW
- │ └─ [User sees streams and selects]
- └─ else:
- └─ filter_audio_streams() (automatic)
- └─ encode with selected streams
-```
-
-## Input Validation
-
-- **Valid**: `1`, `0,1,3`, `2, 3, 5` (spaces OK)
-- **Invalid**: `abc`, `1.5`, `1-3` (ranges not supported)
-- **On Invalid**: Keep all streams, log warning
-
-## Edge Cases Handled
-
-1. **No streams**: Return original (nothing to filter)
-2. **Single stream**: Return as-is (no selection needed)
-3. **Invalid stream indices**: Keep all streams
-4. **Empty input**: Keep all streams
-5. **No valid selections**: Keep all streams (with warning)
-
-## Backward Compatibility
-
-- Existing `--filter-audio` behavior unchanged (automatic mode)
-- `--interactive` is optional, defaults to False
-- No breaking changes to config.xml structure
-- Language tagging (--language) still works alongside audio filtering
diff --git a/INTERACTIVE_AUDIO.md b/INTERACTIVE_AUDIO.md
deleted file mode 100644
index 6298c91..0000000
--- a/INTERACTIVE_AUDIO.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Interactive Audio Stream Selection
-
-## Overview
-The conversion tool now supports **interactive audio stream selection**, allowing you to manually choose which audio tracks to keep during encoding rather than relying on automatic filtering.
-
-## Usage
-
-### Enable Interactive Mode
-Use both `--filter-audio` and `--interactive` flags together:
-
-```bash
-python main.py "C:\path\to\videos" --filter-audio --interactive
-```
-
-### What Happens
-When encoding each file with multiple audio streams:
-
-1. **Audio Stream Display**
- - The tool displays all available audio streams with details:
- ```
- 🎵 AUDIO STREAM SELECTION
- ================================================================================
-
- Stream #0: 2ch | Lang: eng | Bitrate: 128kbps
-
- Stream #1: 6ch | Lang: eng | Bitrate: 448kbps
-
- Stream #2: 2ch | Lang: spa | Bitrate: 128kbps
-
- Stream #3: 2ch | Lang: comment | Bitrate: 64kbps
- ```
-
-2. **User Prompt**
- - You're asked to select which streams to keep:
- ```
- ────────────────────────────────────────────────────────────────────────────
- Enter stream numbers to keep (comma-separated, e.g.: 1,2 or just 2)
- Leave blank to keep all streams
- ────────────────────────────────────────────────────────────────────────────
- ➜ Keep streams: 1,3
- ```
-
-3. **Encoding
-**
- - Only selected streams are included in the encoded output
- - Other streams are removed
- - Selection is logged for reference
-
-## Input Format
-
-- **Multiple streams**: `0,1,3` or `0, 1, 3` (spaces optional)
-- **Single stream**: `1` or `2`
-- **Keep all**: Press Enter without typing anything
-
-## Example Scenarios
-
-### Scenario 1: Keep Main Audio Only
-```
-Streams:
- Stream #0: 2ch (English, 128kbps)
- Stream #1: 6ch (English Surround, 448kbps) ← Best quality
- Stream #2: 2ch (Spanish, 128kbps)
-
-Input: 1
-
-Result: Only Stream #1 (6ch English Surround) is encoded
-```
-
-### Scenario 2: Keep Multiple Languages
-```
-Streams:
- Stream #0: 2ch (English, 128kbps)
- Stream #1: 6ch (English Surround, 448kbps)
- Stream #2: 2ch (Spanish, 128kbps)
- Stream #3: 2ch (Commentary, 64kbps)
-
-Input: 1,2,3
-
-Result: Streams #1, #2, and #3 are encoded (English Surround, Spanish, Commentary)
-```
-
-## Comparison with Automatic Filtering
-
-### Automatic Mode (--filter-audio only)
-- Keeps: Best English audio + all Commentary tracks
-- No user interaction
-- Faster batch processing
-
-### Interactive Mode (--filter-audio --interactive)
-- Shows all streams and asks user to choose
-- Per-file control
-- Better for selective archiving/organization
-- Useful when automatic filtering doesn't match your preferences
-
-## Logging
-
-All user selections are logged to the conversion log for reference:
-```
-User selected 2 audio stream(s): [1, 3]
-Removed 1 audio stream(s): [2]
-```
-
-## Notes
-
-- Interactive mode requires `--filter-audio` to be enabled
-- If you use `--interactive` without `--filter-audio`, filtering is automatically enabled
-- Invalid input (non-existent stream numbers) falls back to keeping all streams
-- Empty input keeps all audio streams unchanged
-- The prompt appears for each file being encoded, allowing different selections per file
diff --git a/LOGGING_STRUCTURE.md b/LOGGING_STRUCTURE.md
deleted file mode 100644
index bf8abe9..0000000
--- a/LOGGING_STRUCTURE.md
+++ /dev/null
@@ -1,101 +0,0 @@
-# Structured Logging with Media Context
-
-## Overview
-
-The conversion system now uses **structured JSON logging** to enable organized analysis and filtering of conversion results by media type, show name, season, and episode.
-
-## Terminal vs Log Output
-
-- **Terminal Output**: Clean, human-readable print statements (VIDEO/AUDIO/PROGRESS sections)
-- **Log Output**: Rich structured JSON with full media context for programmatic analysis
-
-## Media Context Fields
-
-Extracted automatically from file path structure:
-
-```python
-{
- "video_filename": "episode01.mkv",
- "media_type": "tv", # "tv", "anime", "movie", or "other"
- "show_name": "Breaking Bad",
- "season": "01", # Optional (TV/anime only)
- "episode": "01" # Optional (TV/anime only)
-}
-```
-
-## Usage Examples
-
-### Path Structure Recognition
-
-**TV Show**:
-```
-P:\tv\Breaking Bad\season01\episode01.mkv
-→ media_type: "tv", show_name: "Breaking Bad", season: "01", episode: "01"
-```
-
-**Anime**:
-```
-P:\anime\Demon Slayer\season02\e12.mkv
-→ media_type: "anime", show_name: "Demon Slayer", season: "02", episode: "12"
-```
-
-**Movie**:
-```
-P:\movies\Inception.mkv
-→ media_type: "movie", show_name: "Inception"
-```
-
-## Log Output Format
-
-JSON logs contain both the message and media context:
-
-```json
-{
- "timestamp": "2026-02-22 15:30:45",
- "level": "INFO",
- "message": "✅ CONVERSION COMPLETE: episode01[EHX].mkv",
- "video_filename": "episode01.mkv",
- "media_type": "tv",
- "show_name": "Breaking Bad",
- "season": "01",
- "episode": "01",
- "method": "CQ",
- "original_size_mb": 4096.5,
- "output_size_mb": 1843.2,
- "reduction_pct": 55.0
-}
-```
-
-## Filtering Logs Later
-
-You can parse the JSON logs to group by show/season/episode:
-
-```python
-import json
-
-# Filter all Breaking Bad conversions
-with open("logs/conversion.log") as f:
- for line in f:
- entry = json.loads(line)
- if entry.get("show_name") == "Breaking Bad":
- print(f"S{entry['season']}E{entry['episode']}: {entry['reduction_pct']}% reduction")
-```
-
-## Current Implementation
-
-**Files Updated**:
-- `core/process_manager.py`:
- - Added `get_media_context()` function to parse file paths
- - Extracts media context once per file processing
- - Passes context to all logging calls via `extra={}` parameter
-
-- `core/logger_helper.py`:
- - JsonFormatter automatically includes all extra fields in output
- - Added `log_event()` helper for consistent structured logging
-
-## Best Practices
-
-1. Always call `get_media_context()` once per file
-2. Pass result to all logging calls for that file: `logger.info(msg, extra=media_context)`
-3. For additional context: `logger.info(msg, extra={**media_context, "custom_field": value})`
-4. Parse logs with JSON reader for reliable data extraction
diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md
deleted file mode 100644
index 094c1b3..0000000
--- a/PROJECT_STRUCTURE.md
+++ /dev/null
@@ -1,184 +0,0 @@
-# AV1 Batch Video Transcoder - Project Structure
-
-## Overview
-A modular batch AV1 video transcoding system using NVIDIA's av1_nvenc codec (8-bit yuv420p) 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 p7, pix_fmt yuv420p)
- - 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
diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md
deleted file mode 100644
index f4e6009..0000000
--- a/QUICK_REFERENCE.md
+++ /dev/null
@@ -1,182 +0,0 @@
-# Interactive Audio Selection - Quick Reference
-
-## Command Syntax
-
-### Enable Interactive Audio Selection
-```bash
-python main.py "C:\path\to\videos" --filter-audio --interactive
-```
-
-### Other Flags (Optional)
-```bash
---filter-audio --interactive --cq 28 --r 1080 --language eng --test
-```
-
-## What User Sees
-
-### Per File Prompt (appears for each video)
-```
-================================================================================
-🎵 AUDIO STREAM SELECTION
-================================================================================
-
-Stream #0: 2ch | Lang: eng | Bitrate: 128kbps
-
-Stream #1: 6ch | Lang: eng | Bitrate: 448kbps
-
-Stream #2: 2ch | Lang: spa | Bitrate: 128kbps
-
-Stream #3: 2ch | Lang: comment | Bitrate: 64kbps
-
-────────────────────────────────────────────────────────────────────────────
-Enter stream numbers to keep (comma-separated, e.g.: 1,2 or just 2)
-Leave blank to keep all streams
-────────────────────────────────────────────────────────────────────────────
-➜ Keep streams:
-```
-
-### User Input Examples
-
-| Input | Result |
-|-------|--------|
-| `1` | Keep Stream #1 (6ch English, 448kbps) |
-| `1,3` | Keep Streams #1 and #3 |
-| `0,1,2` | Keep Streams #0, #1, and #2 |
-| ` ` (blank) | Keep all 4 streams |
-
-### Expected Output
-```
-✅ Keeping 1 stream(s), removing 3 stream(s)
-
-🎬 Running CQ encode: output.mkv
-...
-```
-
-## Features
-
-✅ **Per-File Control**: Different selections for each video
-✅ **Clear Display**: See channel count, language, bitrate for each stream
-✅ **Flexible Input**: Comma-separated numbers, optional spaces
-✅ **Safe Defaults**: Invalid input keeps all streams
-✅ **Logging**: All selections recorded in conversion log
-✅ **Backwards Compatible**: Doesn't break existing workflows
-
-## Common Scenarios
-
-### Movie with Multiple Audio Tracks
-```
-Stream #0: 2ch English (128kbps)
-Stream #1: 6ch English Surround (448kbps) ← Main audio
-Stream #2: 2ch Spanish (128kbps)
-Stream #3: 2ch Commentary (64kbps)
-
-Input: 1,3
-Output: Keep English 5.1 + Commentary
-```
-
-### TV Episode with Multiple Languages
-```
-Stream #0: 6ch English (384kbps)
-Stream #1: 6ch Spanish (384kbps)
-Stream #2: 2ch Commentary (64kbps)
-
-Input: 0,1,2
-Output: Keep all (English, Spanish, Commentary)
-```
-
-### File with Only One Audio Track
-```
-Stream #0: 6ch English (448kbps)
-
-Input: (blank or 0)
-Output: Keep the only track
-```
-
-## FAQ
-
-**Q: What if I provide an invalid stream number?**
-A: The tool keeps all streams and logs a warning.
-
-**Q: Can I specify stream ranges like "0-2"?**
-A: No, use comma-separated individual numbers: "0,1,2"
-
-**Q: Do I have to answer the prompt for every file?**
-A: Yes, this allows different selections per file. Use automatic --filter-audio mode if you want consistent filtering across all files.
-
-**Q: What happens with invalid input like "abc" or "1.5"?**
-A: The tool keeps all streams and logs the invalid input. Then continues to the next file.
-
-**Q: Does --interactive work alone?**
-A: Yes! If you use --interactive without --filter-audio, filtering is automatically enabled with interactive mode.
-
-**Q: Can I combine this with --language tagging?**
-A: Yes! Use: `--filter-audio --interactive --language eng`
-This lets you select streams AND tag them with language metadata.
-
-## Integration Points
-
-### When Called
-- After audio stream detection in `run_ffmpeg()`
-- Before codec selection and FFmpeg command building
-- Only if `audio_filter_config.enabled = True` AND `audio_filter_config.interactive = True`
-
-### Stream Information Provided
-- **Index**: Stream number in FFmpeg (0-based)
-- **Channels**: 2ch, 6ch, etc.
-- **Language**: eng, spa, und (undefined), etc.
-- **Bitrate**: Detected bitrate in kbps
-
-### What Gets Removed
-- All streams NOT selected by user
-- Metadata and descriptors for removed streams
-- No re-encoding of audio (codec decisions apply per stream)
-
-## Tips & Tricks
-
-### Keeping Only Surround Audio
-Most videos have stereo + surround. To keep only 5.1/6ch:
-```
-Input: 1 (if Stream #1 is 6ch)
-```
-
-### Keeping All Commentary
-Commentary tracks are usually indexed separately:
-```
-Input: 0,2,3 (Stream #0 main + #2 and #3 commentary)
-```
-
-### English Only
-If you have multiple languages:
-```
-Input: 0,1 (Stream #0 and #1 English only)
-```
-
-## Log Output Examples
-
-**Successful Selection**
-```
-User selected 2 audio stream(s): [1, 3]
-Removed 1 audio stream(s): [0, 2]
-```
-
-**Invalid Input**
-```
-User provided invalid audio selection input
-Keeping all audio streams
-```
-
-**No Selection**
-```
-Keeping all audio streams
-```
-
-## Troubleshooting
-
-**Issue**: Prompt doesn't appear
-- **Solution**: Make sure both --filter-audio AND --interactive are specified
-
-**Issue**: Selection is ignored
-- **Solution**: Check log file for errors. Verify stream indices exist.
-
-**Issue**: Want automatic mode back
-- **Solution**: Use --filter-audio alone (without --interactive)
diff --git a/README.md b/README.md
index 1e8bb9f..a1bb447 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,57 @@
# AV1 Batch Video Transcoder
-A high-performance batch video transcoding tool using NVIDIA's **AV1 NVENC** codec with intelligent audio/subtitle handling and automatic quality optimization.
+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
-- **8-bit AV1 Encoding** - NVIDIA GPU acceleration (yuv420p, preset p7)
-- **Smart Audio Processing** - Auto-detects bitrate, AAC for stereo, EAC3 for 5.1, downmixes, re-encodes only when needed
-- **Audio Filtering** - Keep only best English audio + Commentary tracks (remove other languages)
+### 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)
-- **Smart Resolution** - Scales 4K→1080p, preserves lower resolutions
-- **Two-Phase Encoding** - CQ mode first, automatic Bitrate fallback if size threshold exceeded
+- **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
-- **Optional Language Tagging** - Tag audio streams with language codes
-- **CSV Tracking** - Detailed conversion logs with compression ratios
+- **Structured Logging** - JSON logs with media type, show name, season/episode context
+- **File Tagging** - Output files get ` - [EHX]` suffix for easy identification
+
+---
## 🚀 Quick Start
@@ -22,7 +60,7 @@ A high-performance batch video transcoding tool using NVIDIA's **AV1 NVENC** cod
- **Python 3.8+**
- **FFmpeg** with libfdk-aac support
- **NVIDIA GPU** (GeForce RTX 2060+, Quadro, or newer)
-- **NVIDIA CUDA Toolkit** (for av1_nvenc support)
+- **NVIDIA CUDA Toolkit** (for NVENC support)
### Installation
@@ -38,9 +76,12 @@ cd conversion_project
### Basic Usage
```bash
-# Encode a TV folder (smart mode)
+# 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
@@ -55,27 +96,607 @@ 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
```
-## 📖 Documentation
+---
-- **[Full Usage Guide](README_RESTRUCTURE.md)** - Detailed commands, features, troubleshooting
-- **[Technical Architecture](PROJECT_STRUCTURE.md)** - Module breakdown, workflow, config reference
+## 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:
+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:**
@@ -154,14 +1035,27 @@ Show.S01E01 - [EHX].mkv (450MB, subtitle embedded, audio tagged)
- Adjust CQ values in config.xml per content type
- Use `--cq` override: `python main.py folder --cq 30`
-See [Full Guide](README_RESTRUCTURE.md) for more help.
+**"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
-
-## 📞 Support
-
-For detailed usage, see [README_RESTRUCTURE.md](README_RESTRUCTURE.md)
-
-For technical architecture, see [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md)
diff --git a/README_RESTRUCTURE.md b/README_RESTRUCTURE.md
deleted file mode 100644
index 22b0c56..0000000
--- a/README_RESTRUCTURE.md
+++ /dev/null
@@ -1,184 +0,0 @@
-# AV1 Batch Video Transcoder
-
-A clean, modular batch video transcoding system using NVIDIA's AV1 NVENC codec with intelligent audio and subtitle handling.
-
-## 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
-│ ├── process_manager.py - Main transcoding orchestration
-│ ├── encode_engine.py - FFmpeg command builder and execution
-│ ├── audio_handler.py - Audio stream analysis and bitrate decisions
-│ ├── 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 (kept separate from conversion)
-│ ├── gui_path_manager.py
-│ ├── transcode.bat
-│ ├── paths.txt
-│ └── cache/
-│
-├── logs/ - Log files and conversion tracker CSV
-├── processing/ - Temporary encoding files (cleaned up after move)
-└── cache/ (removed) - Folder cache now in /path_manager/cache
-```
-
-## Quick Start
-
-### Basic Usage
-
-```bash
-# Encode a folder (smart mode: CQ first, bitrate fallback if size exceeds 75%)
-python main.py "P:\tv\Show Name"
-
-# Force CQ mode with specific quality
-python main.py "P:\movies\Movie" --cq 30
-
-# Force Bitrate mode
-python main.py "P:\tv\Show" --m bitrate
-
-# Explicit resolution
-python main.py "P:\movies\Movie" --r 1080
-
-# Test mode: encode first file only, show compression ratio, don't move files
-python main.py "P:\tv\Show" --test
-
-# Optional: tag audio streams with language code
-python main.py "P:\tv\Show" --language eng
-```
-
-## Features
-
-- **Hardware Encoding**: NVIDIA av1_nvenc (8-bit yuv420p, preset p7)
-- **Smart Audio**: Analyzes streams, re-encodes excessive bitrate, preserves good quality
-- **Smart Video**: Detects source resolution, scales 4K→1080p, preserves lower resolutions
-- **Subtitle Detection**: Auto-finds and embeds subtitles (vtt, srt, ass, ssa, sub)
- - Supports language-prefixed files: `movie.en.vtt`, `movie.eng.vtt`
- - Cleans up subtitle files after embedding
-- **Two-Phase Encoding** (smart mode):
- - Phase 1: Try CQ mode for quality
- - Phase 2: Retry failed files with Bitrate mode
-- **File Tagging**: Encodes output with ` - [EHX]` suffix
-- **CSV Tracking**: Detailed conversion log with compression ratios
-- **Automatic Cleanup**: Deletes originals + subtitles after successful move
-
-## Configuration
-
-Edit `config.xml` to customize:
-- **CQ Values**: Per content type (tv_1080, tv_720, movie_1080, movie_720)
-- **Audio Buckets**: Bitrate targets for stereo/multichannel
-- **Fallback Bitrates**: Used in Phase 2 bitrate retry
-- **Subtitle Settings**: Extensions to detect, codec for embedding
-- **Path Mappings**: Windows ↔ Linux path conversion (optional)
-
-## Encoding Process (Per File)
-
-1. **Detect subtitles**: Looks for matching `.en.vtt`, `.srt`, etc.
-2. **Analyze source**: Resolution, audio streams, bitrates
-3. **FFmpeg encode**:
- - Video: AV1 NVENC (8-bit yuv420p)
- - Audio: Per-stream decisions (copy or re-encode)
- - Subtitles: Embedded as SRT (if found)
-4. **Size check**: Compare output vs original (default 75% threshold)
-5. **Move file**: From temp folder → original location with `- [EHX]` suffix
-6. **Cleanup**: Delete original file + subtitle file
-
-## Audio Encoding Logic
-
-```
-Stereo audio?
-├─ YES + 1080p: [>192kbps] ENCODE to 192k AAC, [≤192k] COPY
-├─ YES + 720p: [>160kbps] ENCODE to 160k AAC, [≤160k] COPY
-└─ NO (Multichannel): ENCODE to 384k/448k AAC (5.1)
-```
-
-## Removed Features
-
-- ❌ Sonarr/Radarr integration (was complex, removed for simplicity)
-- ❌ Auto-rename based on Sonarr metadata
-- ❌ Web UI (kept separate if needed in future)
-- ❌ Rename functionality (moved to `/rename` folder)
-
-## Advanced Options
-
-### Test Mode
-
-Encodes first file only, shows compression ratio, leaves file in temp folder:
-
-```bash
-python main.py "P:\tv\Show" --test
-```
-
-Useful for: Testing CQ values, checking quality before batch conversion.
-
-### Language Tagging (Optional)
-
-Only tags audio if explicitly provided:
-
-```bash
-python main.py "P:\tv\Show" --language eng
-```
-
-Without `--language` flag, original audio metadata is preserved.
-
-### Resolution Override
-
-Force specific output resolution:
-
-```bash
-python main.py "P:\movies" --r 720 # Force 720p
-python main.py "P:\tv" --r 1080 # Force 1080p
-```
-
-## Output Examples
-
-**Input File:**
-```
-SupernaturalS07E21.mkv (size: 1.5GB)
-SupernaturalS07E21.en.vtt (subtitle)
-```
-
-**Output:**
-```
-SupernaturalS07E21 - [EHX].mkv (size: 450MB, subtitle embedded)
-(original files deleted)
-```
-
-## Troubleshooting
-
-### Wrong Bitrate
-
-Check CQ values in config.xml or use `--cq` override:
-
-```bash
-python main.py "P:\tv\Show" --cq 31
-```
-
-### Subtitles Not Embedding
-
-- Verify file is named correctly: `filename.en.vtt` or `filename.vtt`
-- Check `config.xml` has subtitles enabled and extensions listed
-- Check logs for "Found subtitle" message
-
-### Files Not Moving
-
-Check if reduction ratio threshold (default 0.75) is exceeded:
-
-```bash
-python main.py "P:\tv\Show" --test # Check ratio in Phase 1
-```
-
-If ratio is high, lower CQ value or use bitrate mode.
-
-## Logs
-
-- `logs/conversion.log`: Detailed encoding info, errors, decisions
-- `logs/conversion_tracker.csv`: Summary table of all conversions
-- `logs/conversion_failures.log`: Failed file tracking
diff --git a/config.xml b/config.xml
index f1b2642..d6ff773 100644
--- a/config.xml
+++ b/config.xml
@@ -11,6 +11,10 @@
- [EHX]
+
+
+
+
.mkv,.mp4
@@ -23,8 +27,9 @@
true
- .vtt,.srt,.ass,.ssa,.sub
+ .vtt,.srt,.ass,.ssa,.sub,.mov
srt
+
@@ -36,15 +41,24 @@
eng
+
+
+
+
+ eng
+
+
+
+ true
-
-
-
+
+
+