major improvements
This commit is contained in:
parent
6b46f4aa33
commit
7e77f85b5f
422
ARCHITECTURE.md
422
ARCHITECTURE.md
@ -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.
|
|
||||||
@ -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
|
|
||||||
<encoder default="nvenc">
|
|
||||||
<av1_nvenc preset="p7" bit_depth="8" pix_fmt="yuv420p" />
|
|
||||||
<hevc_nvenc preset="slow" bit_depth="10" pix_fmt="yuv420p10le" />
|
|
||||||
</encoder>
|
|
||||||
```
|
|
||||||
|
|
||||||
The `default="nvenc"` attribute can be changed, but CLI `--encoder` flag always takes precedence.
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
1. **config.xml** - Added `<encoder>` 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.
|
|
||||||
@ -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.
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
<general>
|
|
||||||
<processing_folder>processing</processing_folder>
|
|
||||||
<suffix> - [EHX]</suffix>
|
|
||||||
<extensions>.mkv,.mp4</extensions>
|
|
||||||
<reduction_ratio_threshold>0.75</reduction_ratio_threshold>
|
|
||||||
<subtitles>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
<extensions>.vtt,.srt,.ass,.ssa,.sub</extensions>
|
|
||||||
<codec>srt</codec>
|
|
||||||
</subtitles>
|
|
||||||
</general>
|
|
||||||
|
|
||||||
<encode>
|
|
||||||
<cq>
|
|
||||||
<tv_1080>28</tv_1080>
|
|
||||||
<tv_720>32</tv_720>
|
|
||||||
<movie_1080>32</movie_1080>
|
|
||||||
<movie_720>34</movie_720>
|
|
||||||
</cq>
|
|
||||||
</encode>
|
|
||||||
|
|
||||||
<audio>
|
|
||||||
<stereo>
|
|
||||||
<high>192000</high>
|
|
||||||
<medium>160000</medium>
|
|
||||||
</stereo>
|
|
||||||
<multi_channel>
|
|
||||||
<medium>448000</medium>
|
|
||||||
<low>384000</low>
|
|
||||||
</multi_channel>
|
|
||||||
</audio>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
|
||||||
@ -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)
|
|
||||||
@ -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
|
|
||||||
27
config.xml
27
config.xml
@ -11,6 +11,10 @@
|
|||||||
<!-- File suffix added to encoded outputs -->
|
<!-- File suffix added to encoded outputs -->
|
||||||
<suffix> - [EHX]</suffix>
|
<suffix> - [EHX]</suffix>
|
||||||
|
|
||||||
|
<!-- Optional title suffix inserted before main suffix (e.g., quality or version info) -->
|
||||||
|
<!-- Leave empty or remove to disable. Example: " 1080p" results in "filename 1080p - [EHX].mkv" -->
|
||||||
|
<title_suffix></title_suffix>
|
||||||
|
|
||||||
<!-- Allowed input extensions -->
|
<!-- Allowed input extensions -->
|
||||||
<extensions>.mkv,.mp4</extensions>
|
<extensions>.mkv,.mp4</extensions>
|
||||||
|
|
||||||
@ -23,8 +27,9 @@
|
|||||||
<!-- Subtitle settings -->
|
<!-- Subtitle settings -->
|
||||||
<subtitles>
|
<subtitles>
|
||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
<extensions>.vtt,.srt,.ass,.ssa,.sub</extensions>
|
<extensions>.vtt,.srt,.ass,.ssa,.sub,.mov</extensions>
|
||||||
<codec>srt</codec>
|
<codec>srt</codec>
|
||||||
|
<!-- Note: mov_text (embedded in MP4/MOV) will be automatically converted to SRT -->
|
||||||
</subtitles>
|
</subtitles>
|
||||||
|
|
||||||
<!-- Audio track filtering: keep only best English audio + Commentary -->
|
<!-- Audio track filtering: keep only best English audio + Commentary -->
|
||||||
@ -36,15 +41,24 @@
|
|||||||
|
|
||||||
<!-- Audio language tag -->
|
<!-- Audio language tag -->
|
||||||
<audio_language>eng</audio_language>
|
<audio_language>eng</audio_language>
|
||||||
|
|
||||||
|
<!-- Default language for undefined (und) audio tracks -->
|
||||||
|
<!-- When an audio track has no language tag (und), it will be replaced with this language -->
|
||||||
|
<!-- Set to desired ISO 639-2 code (eng, spa, fra, deu, etc.). Set to 'und' to disable replacement -->
|
||||||
|
<default_language>eng</default_language>
|
||||||
|
|
||||||
|
<!-- Replace undefined language tracks with default language -->
|
||||||
|
<!-- When true and audio has 'und' language tag, it will be replaced with default_language -->
|
||||||
|
<replace_undefined_language>true</replace_undefined_language>
|
||||||
</general>
|
</general>
|
||||||
|
|
||||||
<!-- =============================
|
<!-- =============================
|
||||||
PATH MAPPINGS (Windows → Linux)
|
PATH MAPPINGS (Windows to Linux)
|
||||||
============================= -->
|
============================= -->
|
||||||
<path_mappings>
|
<path_mappings>
|
||||||
<map from="P:\tv" to="/mnt/plex/tv" />
|
<map from="P:\\tv" to="/mnt/plex/tv" />
|
||||||
<map from="P:\anime" to="/mnt/plex/anime" />
|
<map from="P:\\anime" to="/mnt/plex/anime" />
|
||||||
<map from="P:\movies" to="/mnt/plex/movies" />
|
<map from="P:\\movies" to="/mnt/plex/movies" />
|
||||||
</path_mappings>
|
</path_mappings>
|
||||||
|
|
||||||
<!-- =============================
|
<!-- =============================
|
||||||
@ -58,6 +72,7 @@
|
|||||||
<tv_720>30</tv_720>
|
<tv_720>30</tv_720>
|
||||||
<anime_1080>32</anime_1080>
|
<anime_1080>32</anime_1080>
|
||||||
<anime_720>30</anime_720>
|
<anime_720>30</anime_720>
|
||||||
|
<movie_2160>29</movie_2160>
|
||||||
<movie_1080>32</movie_1080>
|
<movie_1080>32</movie_1080>
|
||||||
<movie_720>30</movie_720>
|
<movie_720>30</movie_720>
|
||||||
</av1>
|
</av1>
|
||||||
@ -66,6 +81,7 @@
|
|||||||
<tv_720>26</tv_720>
|
<tv_720>26</tv_720>
|
||||||
<anime_1080>28</anime_1080>
|
<anime_1080>28</anime_1080>
|
||||||
<anime_720>26</anime_720>
|
<anime_720>26</anime_720>
|
||||||
|
<movie_2160>25</movie_2160>
|
||||||
<movie_1080>28</movie_1080>
|
<movie_1080>28</movie_1080>
|
||||||
<movie_720>26</movie_720>
|
<movie_720>26</movie_720>
|
||||||
</hevc>
|
</hevc>
|
||||||
@ -101,6 +117,7 @@
|
|||||||
<multi_channel>
|
<multi_channel>
|
||||||
<low>384000</low>
|
<low>384000</low>
|
||||||
<medium>448000</medium>
|
<medium>448000</medium>
|
||||||
|
<high>640000</high>
|
||||||
</multi_channel>
|
</multi_channel>
|
||||||
</audio>
|
</audio>
|
||||||
|
|
||||||
|
|||||||
@ -1907,3 +1907,943 @@ tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E22 - Monkey (
|
|||||||
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E01 - Zoo (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.49,730.19,86.0,1920x1080,1920x1080,1,28,CQ
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E01 - Zoo (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.49,730.19,86.0,1920x1080,1920x1080,1,28,CQ
|
||||||
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E02 - Humilithon (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.38,719.01,84.7,1920x1080,1920x1080,1,28,CQ
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E02 - Humilithon (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.38,719.01,84.7,1920x1080,1920x1080,1,28,CQ
|
||||||
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E03 - Family Reunion (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.79,713.97,84.0,1920x1080,1920x1080,1,28,CQ
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E03 - Family Reunion (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.79,713.97,84.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
movie,N/A,The.Hammer.2023.1080p.WEBRip.x264.AAC-LAMA - [EHX].mkv,1530.75,904.44,59.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
movie,N/A,Sunshine (2007) h264 DTS-HD MA 5.1 Bluray-1080p Radarr - [EHX].mkv,28789.49,1357.08,4.7,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E01 - Traffic Jam (2) (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,863.19,522.61,60.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E01 - Pilot (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,748.56,405.87,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E02 - Red Dress (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,720.88,376.75,52.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E03 - Home Alone 4 (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,680.96,358.58,52.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E04 - Shame (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,625.17,324.82,52.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E05 - Malcolm Babysits (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,675.54,350.61,51.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E06 - Sleepover (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,593.74,292.16,49.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E07 - Francis Escapes (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,759.32,410.03,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E08 - Krelboyne Picnic (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,692.2,383.74,55.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E09 - Lois vs. Evil (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,707.9,387.19,54.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E10 - Stock Car Races (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,827.53,460.3,55.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E11 - Funeral (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,640.42,326.92,51.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E12 - Cheerleader (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,706.16,374.54,53.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E13 - Rollerskates (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,663.27,351.02,52.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E14 - The Bots and the Bees (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,684.2,369.44,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E15 - Smunday (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,689.08,368.05,53.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S01E16 - Water Park (1) (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,754.21,420.33,55.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E02 - Halloween Approximately (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,629.67,325.45,51.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E03 - Lois's Birthday (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,678.31,369.15,54.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E04 - Dinner Out (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,693.15,367.86,53.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E05 - Casino (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,713.62,389.07,54.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E06 - Convention (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,654.11,339.65,51.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E07 - Robbery (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,574.79,280.7,48.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E08 - Therapy (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,628.39,329.75,52.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E09 - High School Play (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,618.99,335.21,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E10 - The Bully (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,624.12,336.79,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E11 - Old Mrs. Old (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,562.62,294.11,52.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E12 - Krelboyne Girl (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,618.82,321.91,52.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E13 - New Neighbors (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,629.86,341.29,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E14 - Hal Quits (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,545.75,288.92,52.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E15 - The Grandparents (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,518.2,281.97,54.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E16 - Traffic Ticket (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,550.93,293.61,53.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E17 - Surgery (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,590.2,300.67,50.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E18 - Reese Cooks (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,618.58,320.68,51.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E19 - Tutoring Reese (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,562.84,296.28,52.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E20 - Bowling (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,618.56,320.6,51.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E21 - Malcolm vs. Reese (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,610.79,312.03,51.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E22 - Mini-Bike (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,657.95,340.24,51.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E23 - Carnival (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,510.18,253.56,49.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E24 - Evacuation (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,649.77,348.49,53.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S02E25 - Flashback (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,715.42,396.22,55.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E01 - Houseboat (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,602.38,332.04,55.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E02 - Emancipation (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,576.08,316.45,54.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E03 - Book Club (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,487.55,241.38,49.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E04 - Malcolm's Girlfriend (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,561.32,304.77,54.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E05 - Charity (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,491.01,257.9,52.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E06 - Health Scare (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,499.26,259.33,51.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E07 - Christmas (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,494.53,253.3,51.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E08 - Poker (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,534.68,274.08,51.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E09 - Reese's Job (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,554.92,290.52,52.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E10 - Lois's Makeover (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,588.49,319.81,54.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E11 - Company Picnic (Part 1) (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,668.58,369.02,55.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E12 - Company Picnic (Part 2) (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,772.78,441.79,57.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E13 - Reese Drives (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,527.77,280.6,53.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E14 - Cynthia's Back (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,579.04,303.41,52.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E15 - Hal's Birthday (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,583.03,303.55,52.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E16 - Hal Coaches (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,654.13,361.25,55.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E17 - Dewey's Dog (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,564.4,288.87,51.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E18 - Poker #2 (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,549.25,276.83,50.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E19 - Clip Show (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,629.34,332.62,52.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E20 - Jury Duty (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,531.74,281.39,52.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E21 - Cliques (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,612.59,328.25,53.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S03E22 - Monkey (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,579.38,304.31,52.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E01 - Zoo (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,730.19,409.9,56.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E02 - Humilithon (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,719.01,405.53,56.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E03 - Family Reunion (1080p AMZN WEB-DL x265 Silence) - [EHX] - [EHX].mkv,713.97,393.1,55.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E04 - Stupid Girl (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.33,370.05,43.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E05 - Forwards Backwards (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.5,419.2,49.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E06 - Forbidden Girlfriend (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.41,442.33,52.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E07 - Malcolm Holds His Tongue (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.2,412.83,48.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E08 - Boys at Ranch (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.09,419.41,49.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E09 - Grandma Sues (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,828.26,370.89,44.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E10 - If Boys Were Girls (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.5,480.13,56.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E11 - Long Drive (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.4,388.5,45.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E12 - Kicked Out (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.25,396.88,46.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E13 - Stereo Store (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.96,396.4,46.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E14 - Hal's Friend (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.21,411.67,48.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E15 - Garage Sale (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.1,472.18,55.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E16 - Academic Octathalon (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.59,395.22,46.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E17 - Clip Show #2 (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,850.03,408.64,48.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E18 - Reese's Party (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.89,439.86,51.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E19 - Future Malcolm (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.78,458.76,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E20 - Baby (Part 1) (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,872.55,455.74,52.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E21 - Baby (Part 2) (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,854.83,444.28,52.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S04E22 - Day Care (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,831.66,416.73,50.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E01 - Vegas (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,868.62,354.63,40.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E02 - Watching the Baby (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.1,414.62,48.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E03 - Goodbye Kitty (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.63,400.98,47.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E04 - Thanksgiving (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,833.75,386.56,46.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E05 - Malcolm Films Reese (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,839.41,376.47,44.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E06 - Malcolm's Job (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,833.26,377.37,45.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E07 - Christmas Trees (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,840.01,416.36,49.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E08 - Block Party (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.87,453.74,53.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E09 - Dirty Magazine (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.42,380.96,44.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E10 - Hot Tub (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.41,364.77,42.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E11 - Ida's Boyfriend (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,847.57,361.04,42.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E12 - Softball (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.74,388.64,45.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E13 - Lois's Sister (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.54,298.99,35.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E14 - Malcolm Dates a Family (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.74,312.34,36.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E15 - Reese's Apartment (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.63,301.67,35.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E16 - Malcolm Visits College (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.57,369.89,43.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E17 - Polly in the Middle (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.5,326.39,38.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E18 - Dewey's Special Class (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.97,376.47,44.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E19 - Experiment (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,841.67,319.57,38.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E20 - Victor's Other Family (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.32,319.92,37.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E21 - Reese Joins The Army (Part 1) (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.21,343.82,40.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S05E22 - Reese Joins The Army (Part 2) (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.65,306.27,36.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E01 - Reese Comes Home (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,836.39,427.95,51.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E02 - Buseys Run Away (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.86,432.29,51.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E03 - Standee (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.96,401.03,47.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E04 - Pearl Harbor (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.24,399.72,47.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E05 - Kitty's Back (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,864.36,392.81,45.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E06 - Hal's Christmas Gift (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.08,380.69,44.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E07 - Hal Sleepwalks (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.27,438.36,51.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E08 - Lois Battles Jamie (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,843.84,394.17,46.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E09 - Malcolm's Car (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,844.34,456.21,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E10 - Billboard (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,846.17,399.84,47.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E11 - Dewey's Opera (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,863.55,404.91,46.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E12 - Living Will (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.66,446.13,52.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E13 - Tiki Lounge (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,844.2,416.31,49.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E14 - Ida Loses A Leg (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,846.43,473.89,56.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E15 - Chad's Sleepover (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,844.62,437.22,51.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E16 - No Motorcycles (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,844.75,464.56,55.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E17 - Butterflies (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,840.89,455.39,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E18 - Ida's Dance (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.92,468.57,55.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E19 - Motivational Seminar (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,844.28,392.11,46.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E20 - Stilts (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,878.48,471.14,53.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E21 - Buseys Take a Hostage (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.88,441.71,52.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S06E22 - Mrs. Tri-County (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,864.43,462.63,53.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E01 - Burning Man (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.52,463.46,54.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E02 - Health Insurance (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,832.22,454.45,54.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E03 - Reese vs. Stevie (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,850.6,394.2,46.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E04 - Halloween (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,780.9,367.72,47.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E05 - Jessica Stays Over (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,847.74,432.36,51.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E06 - Secret Boyfriend (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.5,448.82,52.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E07 - Blackout (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,868.1,442.94,51.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E08 - Army Buddy (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.33,450.79,53.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E09 - Malcolm Defends Reese (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.69,443.76,52.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E10 - Malcolm's Money (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,845.08,469.49,55.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E11 - Bride of Ida (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,867.96,465.72,53.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E12 - College Recruiters (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.03,451.83,53.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E13 - Mono (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,850.37,459.03,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E14 - Hal Grieves (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,868.47,440.91,50.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E15 - A.A. (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,846.41,453.65,53.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E16 - Lois Strikes Back (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.08,437.46,51.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E17 - Hal's Dentist (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,828.0,432.91,52.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E18 - Bomb Shelter (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,850.34,490.52,57.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E19 - Stevie in the Hospital (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,850.1,483.45,56.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E20 - Cattle Court (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,848.89,464.64,54.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E21 - Morp (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,849.52,460.27,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Malcolm in the Middle (2000),Malcolm in the Middle (2000) - S07E22 - Graduation (1080p AMZN WEB-DL x265 Silence) - [EHX].mkv,871.17,467.92,53.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
movie,N/A,How to Make a Killing (2026) x265 EAC3 Atmos 5.1 WEBDL-1080p Ghost - [EHX].mkv,4169.36,1915.96,46.0,1920x800,1920x800,1,28,CQ
|
||||||
|
movie,N/A,The Shadow's Edge (2025) (1080p BluRay x265 SAMPA - [EHX].mkv,6747.8,2284.6,33.9,1920x804,1920x804,2,28,CQ
|
||||||
|
movie,N/A,Gallery.mkv,30.08,27.1,90.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
movie,N/A,Menu.mkv,7.67,6.4,83.4,1920x894,1920x894,1,28,CQ
|
||||||
|
movie,N/A,Trailer 2.mkv,29.02,27.3,94.1,1920x904,1920x904,1,28,CQ
|
||||||
|
movie,N/A,Trailer 3.mkv,35.52,32.77,92.3,1920x904,1920x904,1,28,CQ
|
||||||
|
movie,N/A,Trailer 4.mkv,64.25,45.06,70.1,1920x802,1920x802,1,28,CQ
|
||||||
|
movie,N/A,The Housemaid (2025) x265 EAC3 Atmos 8.0 Bluray-1080p Silence - [EHX].mkv,8112.35,1679.09,20.7,1920x800,1280x720,4,26,CQ
|
||||||
|
movie,N/A,Avatar - Fire and Ash (2025) x265 EAC3 Atmos 5.1 WEBDL-1080p Silence - [EHX].mkv,10010.8,6008.06,60.0,1920x1038,1920x1038,1,28,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E01 - Tojima Wants to Be a Kamen Rider x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1546.04,338.2,21.9,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E02 - I Am Tackle! x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1540.03,366.14,23.8,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E03 - I Love The Moment When Hate Turns To Love x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1537.81,346.86,22.6,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E04 - Who is the Strongest Kamen Rider x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1536.87,392.26,25.5,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E05 - Let Me Be V3 Too x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1541.16,425.49,27.6,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E05 - Let Me Be V3 Too x265 EAC3 WEBRip-1080p EMBER - [EHX].mkv,394.18,329.98,83.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E06 - Order Some Snacks x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1536.48,333.42,21.7,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E06 - Order Some Snacks x265 AAC WEBRip-1080p Erai-raws - [EHX].mkv,631.35,258.07,40.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E07 - Please Make Me a Part of Shocker x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1540.78,311.7,20.2,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E08 - What's a Kamen Rider Do When A Dangerous Enemy Appears x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1538.49,319.95,20.8,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E09 - Show Me Your Kamen Rider x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1539.78,432.1,28.1,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E10 - Risk Your Life x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1540.97,437.65,28.4,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E11 - Tackle is the Strongest x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1533.26,400.28,26.1,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E12 - I'll Take All You Riders On x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1537.32,337.51,22.0,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,"Tojima Wants to Be a Kamen Rider - S01E13 - I Will Fight, and Die, Against Shocker x264 AAC WEBDL-1080p VARYG - [EHX].mkv",1539.36,308.25,20.0,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E14 - I Want to Learn More About Humans x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1537.33,324.4,21.1,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,"Tojima Wants to Be a Kamen Rider - S01E15 - The Masked Idol, Heavy Chop x264 AAC WEBDL-1080p VARYG - [EHX].mkv",1542.42,363.47,23.6,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E16 - An Imposter Can't Beat the Real Deal x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1539.75,345.85,22.5,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E17 - Everyone In The World Will Join Shocker x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1533.98,347.43,22.6,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E18 - I'll Fight Shocker Too h264 EAC3 WEBDL-1080p VARYG - [EHX].mkv,913.78,357.07,39.1,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E19 - It'd Be an Honor to Die as a Rider x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1541.74,376.02,24.4,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E20 - I Was Craving a Battle With Shocker x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1539.51,319.82,20.8,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E21 - Becoming the Ultimate Monster x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1543.04,337.91,21.9,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E22 - Shocker Is on the Move x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1536.12,355.91,23.2,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,"Tojima Wants to Be a Kamen Rider - S01E23 - Let's Do This, Shocker! x264 AAC WEBDL-1080p VARYG - [EHX].mkv",1541.06,391.05,25.4,1920x1080,1920x1080,2,32,CQ
|
||||||
|
anime,Tojima Tanzaburo Wants to Be a Kamen Rider,Tojima Wants to Be a Kamen Rider - S01E24 - I Wouldn't Mind Dying Today x264 AAC WEBDL-1080p VARYG - [EHX].mkv,1539.7,431.3,28.0,1920x1080,1920x1080,2,32,CQ
|
||||||
|
movie,N/A,Doom (2005) Unrated x265 AAC 5.1 Bluray-1080p Tigole - [EHX].mkv,5768.6,1524.44,26.4,1920x816,1920x816,1,28,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S01E01 - Episode 1 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2441.61,542.45,22.2,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S01E02 - Episode 2 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2469.07,529.25,21.4,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S01E03 - Episode 3 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2498.13,515.15,20.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S02E01 - Episode 1 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2749.37,653.99,23.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S02E02 - Episode 2 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2748.79,560.6,20.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Karen Pirie (2022),Karen Pirie (2022) - S02E03 - Episode 3 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2767.03,711.31,25.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E01 - Pilot (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1876.52,666.58,35.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E02 - Stuntin' Like My Daddy (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2154.31,828.19,38.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E03 - Made You Look (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2034.93,780.81,38.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E04 - Shook Ones Pt. II (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1985.95,765.04,38.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E05 - '03 Bonnie and Clyde (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1901.43,599.0,31.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E06 - The Next Episode (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1814.6,604.85,33.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E07 - The Trials and Tribulations of Trying to Pee While Depressed (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2147.61,751.78,35.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S01E08 - And Salt the Earth Behind You (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2307.9,817.98,35.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E01 - Trying to Get to Heaven Before They Close the Door (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2133.03,1471.94,69.0,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E02 - Out of Touch (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1987.03,1165.79,58.7,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E03 - Ruminations Big and Little Bullys (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2089.57,1381.63,66.1,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,"Euphoria (2019) - S02E04 - You Who Cannot See, Think of Those Who Can (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv",2160.77,1153.59,53.4,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E05 - Stand Still Like the Hummingbird (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,1883.31,1176.04,62.4,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E06 - A Thousand Little Trees of Blood (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2092.44,1355.37,64.8,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,Euphoria (2019) - S02E07 - The Theater and Its Double (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv,2046.74,1185.46,57.9,1920x1040,1920x1040,1,28,CQ
|
||||||
|
tv,Euphoria,"Euphoria (2019) - S02E08 - All My Life, My Heart Has Yearned for a Thing I Cannot Name (1080p AMZN WEB-DL x265 t3nzin) - [EHX].mkv",2149.38,1445.91,67.3,1920x1040,1920x1040,1,28,CQ
|
||||||
|
movie,N/A,Unknown (2011) (1080p BluRay x265 10bit Tigole) - [EHX].mkv,4300.35,1299.6,30.2,1920x800,1280x720,1,26,CQ
|
||||||
|
movie,N/A,Ferris Bueller's Day Off (1986) (1080p BluRay x265 r00t) - [EHX].mkv,5225.63,2750.29,52.6,1920x816,1920x816,3,28,CQ
|
||||||
|
movie,N/A,Getting the Class Together - The Cast of Ferris Bueller’s Day Off.mkv,284.54,188.0,66.1,720x480,720x480,1,26,CQ
|
||||||
|
movie,N/A,The Making of Ferris Bueller's Day Off.mkv,159.01,115.32,72.5,720x480,720x480,1,26,CQ
|
||||||
|
movie,N/A,The World According to Ben Stein.mkv,111.41,60.3,54.1,720x480,720x480,1,26,CQ
|
||||||
|
movie,N/A,Vintage Ferris Bueller - The Lost Tapes.mkv,105.03,76.72,73.0,720x480,720x480,1,26,CQ
|
||||||
|
movie,N/A,Who is Ferris Bueller.mkv,94.64,69.8,73.8,720x480,720x480,1,26,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E01 - 3AM x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1390.65,597.58,43.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E02 - Two Dead Men x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1637.5,713.87,43.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E03 - Kandahar x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1243.54,578.01,46.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E04 - Resupply x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1096.16,506.82,46.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E05 - Gunner x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1894.5,792.41,41.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E06 - The Judas Goat x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1471.89,577.72,39.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E07 - Crosshairs x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1141.14,494.77,43.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E08 - Cold Steel x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1361.55,581.97,42.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E09 - Front Toward Enemy x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1559.76,653.45,41.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E10 - Virtue of the Vicious x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1317.87,570.2,43.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E11 - Danger Close x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1218.59,561.95,46.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E12 - Home x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1404.58,616.96,43.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S01E13 - Memento Mori x265 AC3 WEBDL-1080p Vyndros - [EHX].mkv,1519.88,775.92,51.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E01 - Roadhouse Blues x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1039.87,568.95,54.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E02 - Fight or Flight x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1013.43,459.7,45.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E03 - Trouble the Water x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,889.57,483.43,54.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E04 - Scar Tissue x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1203.55,597.04,49.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E05 - One-Eyed Jacks x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1029.48,474.43,46.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E06 - Nakazat x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1134.52,571.64,50.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E07 - One Bad Day x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,910.02,475.39,52.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E08 - My Brother's Keeper x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1000.91,514.32,51.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E09 - Flustercluck x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1307.68,562.91,43.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E10 - The Dark Hearts of Men x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,942.91,447.9,47.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E11 - The Abyss x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1228.77,549.33,44.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E12 - Collision Course x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1156.6,595.24,51.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Marvel's The Punisher (2017),Marvel's The Punisher - S02E13 - The Whirlwind x265 EAC3 Atmos WEBDL-1080p Vyndros - [EHX].mkv,1127.57,493.39,43.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E01 - The Red Serpent x265 AAC Bluray-1080p Silence - [EHX].mkv,2172.8,882.35,40.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E02 - Sacramentum Gladiatorum x265 AAC Bluray-1080p Silence - [EHX].mkv,2085.44,767.44,36.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E03 - Legends x265 AAC Bluray-1080p Silence - [EHX].mkv,2140.54,799.18,37.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E04 - The Thing in the Pit x265 AAC Bluray-1080p Silence - [EHX].mkv,1929.66,748.01,38.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E05 - Shadow Games x265 AAC Bluray-1080p Silence - [EHX].mkv,2166.87,756.8,34.9,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E06 - Delicate Things x265 AAC Bluray-1080p Silence - [EHX].mkv,2169.87,780.62,36.0,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E07 - Great and Unfortunate Things x265 AAC Bluray-1080p Silence - [EHX].mkv,1966.65,671.34,34.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E08 - Mark of the Brotherhood x265 AAC Bluray-1080p Silence - [EHX].mkv,1971.43,673.21,34.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E09 - Whore x265 AAC Bluray-1080p Silence - [EHX].mkv,1990.39,701.91,35.3,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E10 - Party Favors x265 AAC Bluray-1080p Silence - [EHX].mkv,2047.89,789.49,38.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E11 - Old Wounds x265 AAC Bluray-1080p Silence - [EHX].mkv,2005.96,792.88,39.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E12 - Revelations x265 AAC Bluray-1080p Silence - [EHX].mkv,2188.12,761.93,34.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S01E13 - Kill Them All x265 AAC Bluray-1080p Silence - [EHX].mkv,2141.36,749.32,35.0,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E01 - Fugitivus x265 AAC Bluray-1080p Silence - [EHX].mkv,2228.46,730.01,32.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E02 - A Place in This World x265 AAC Bluray-1080p Silence - [EHX].mkv,2066.62,678.84,32.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E03 - The Greater Good x265 AAC Bluray-1080p Silence - [EHX].mkv,2087.81,762.8,36.5,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E04 - Empty Hands x265 AAC Bluray-1080p Silence - [EHX].mkv,2353.2,879.24,37.4,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E05 - Libertus x265 AAC Bluray-1080p Silence - [EHX].mkv,2202.52,836.49,38.0,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E06 - Chosen Path x265 AAC Bluray-1080p Silence - [EHX].mkv,2214.16,723.63,32.7,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E07 - Sacramentum x265 AAC Bluray-1080p Silence - [EHX].mkv,2235.69,706.52,31.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E08 - Balance x265 AAC Bluray-1080p Silence - [EHX].mkv,2205.22,696.16,31.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E09 - Monsters x265 AAC Bluray-1080p Silence - [EHX].mkv,2198.19,764.51,34.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S02E10 - Wrath of the Gods x265 AAC Bluray-1080p Silence - [EHX].mkv,2389.52,731.37,30.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E01 - Enemies of Rome x265 AAC Bluray-1080p Silence - [EHX].mkv,2034.53,748.9,36.8,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E02 - Wolves at the Gate x265 AAC Bluray-1080p Silence - [EHX].mkv,2139.02,781.89,36.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E03 - Men of Honor x265 AAC Bluray-1080p Silence - [EHX].mkv,2321.19,821.79,35.4,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E04 - Decimation x265 AAC Bluray-1080p Silence - [EHX].mkv,2246.65,784.12,34.9,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E05 - Blood Brothers x265 AAC Bluray-1080p Silence - [EHX].mkv,2149.93,809.26,37.6,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E06 - Spoils of War x265 AAC Bluray-1080p Silence - [EHX].mkv,2270.85,821.72,36.2,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E07 - Mors Indecepta x265 AAC Bluray-1080p Silence - [EHX].mkv,2181.67,898.73,41.2,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E08 - Separate Paths x265 AAC Bluray-1080p Silence - [EHX].mkv,2211.42,876.34,39.6,1920x1080,1280x720,3,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E09 - The Dead and the Dying x265 AAC Bluray-1080p Silence - [EHX].mkv,2395.15,916.75,38.3,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Spartacus - S03E10 - Victory x265 AAC Bluray-1080p Silence - [EHX].mkv,2402.18,1010.42,42.1,1920x1080,1280x720,2,26,CQ
|
||||||
|
tv,Spartacus,Andy Gets Plastered.mkv,88.32,57.64,65.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Battle Royale.mkv,212.92,119.12,55.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Blood and Sand - Behind-the-Scenes.mkv,308.32,205.57,66.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Exposing Your Ludus.mkv,155.33,109.09,70.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Gladiator Boot Camp.mkv,129.52,85.85,66.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Grime & Punishment - The Hole.mkv,232.35,121.23,52.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Legend Re-Imagined.mkv,91.14,55.85,61.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,"Oh, Those Randy Romans.mkv",121.2,76.35,63.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Shooting Green - The Shadow of Death.mkv,135.55,88.09,65.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Trailer.mkv,25.54,18.17,71.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Behind the Camera - Directing the Rebellion.mkv,156.99,92.74,59.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Blooper reel.mkv,76.51,39.88,52.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Burning Down the House - The VFX of Episode 205.mkv,339.28,245.57,72.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Famous Last Words.mkv,197.89,110.84,56.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,On Set with Liam McIntyre.mkv,201.42,131.31,65.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Starz Studios - Spartacus Vengeance.mkv,404.33,205.25,50.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Legend of Spartacus.mkv,251.32,184.87,73.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Making of Spartacus Vengeance.mkv,181.58,110.13,60.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,A Bloody Farewell.mkv,77.86,45.41,58.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,Adorning the Damned.mkv,107.44,52.04,48.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Legend Retold.mkv,217.24,122.16,56.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Mind Behind SPARTACUS.mkv,180.74,87.26,48.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Price of Being a Gladiator.mkv,89.15,45.31,50.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Spartacus,The Spoils of War Revealed - Visual Effects.mkv,146.08,78.88,54.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E01 - Where You Left Your Heart x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,652.22,308.48,47.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E02 - One Wrong Turn On Bourbon x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,644.08,308.0,47.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E03 - Ne Me Quitte Pas x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,597.6,285.31,47.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E04 - Between the Devil and the Deep Blue Sea x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,655.17,324.83,49.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E05 - Don't It Just Break Your Heart x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,591.58,292.75,49.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),"The Originals - S05E06 - What, Will, I, Have, Left x265 AC3 HDTV-1080p ZMNT - [EHX].mkv",545.69,283.58,52.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E07 - God's Gonna Trouble the Water x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,644.17,317.57,49.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E08 - The Kindness of Strangers x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,565.44,276.33,48.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E09 - We Have Not Long to Love x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,627.93,309.28,49.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E10 - There in the Disappearing Light x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,573.55,281.84,49.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E11 - ‘Til the Day I Die x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,572.21,295.56,51.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E12 - The Tale of Two Wolves x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,613.09,323.95,52.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S05E13 - When the Saints Go Marching In x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,518.53,266.36,51.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E01 - Always and Forever x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,652.83,287.8,44.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E02 - House of the Rising Son x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,770.41,349.89,45.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E03 - Tangled Up in Blue x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,747.72,348.55,46.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E04 - Girl in New Orleans x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,684.89,313.93,45.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E05 - Sinners and Saints x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,808.82,367.6,45.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E06 - Fruit of the Poisoned Tree x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,706.24,323.98,45.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E07 - Bloodletting x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,906.33,409.09,45.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E08 - The River in Reverse x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,590.73,299.73,50.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E09 - Reigning Pain in New Orleans x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,617.14,293.73,47.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E10 - The Casket Girls x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,641.71,324.05,50.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),"The Originals - S01E11 - Après Moi, Le Déluge x265 AC3 HDTV-1080p ZMNT - [EHX].mkv",734.33,371.09,50.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E12 - Dance Back from the Grave x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,899.46,400.74,44.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E13 - Crescent City x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,850.19,382.01,44.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E14 - Long Way Back from Hell x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,937.53,375.42,40.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E15 - Le Grand Guignol x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,883.96,389.2,44.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E16 - Farewell to Storyville x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,748.56,324.52,43.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E17 - Moon Over Bourbon Street x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,835.99,356.22,42.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E18 - The Big Uneasy x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,838.6,384.67,45.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E19 - An Unblinking Death x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,935.77,396.93,42.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E20 - A Closer Walk with Thee x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,877.5,379.61,43.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E21 - The Battle of New Orleans x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,974.3,400.59,41.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S01E22 - From a Cradle to a Grave x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,928.43,400.1,43.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E01 - Rebirth x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,1025.24,383.96,37.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E02 - Alive and Kicking x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,814.31,380.39,46.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E03 - Every Mother's Son x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,781.54,337.54,43.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E04 - Live and Let Die x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,833.09,381.67,45.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E05 - Red Door x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,902.84,406.59,45.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E06 - Wheel Inside the Wheel x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,888.5,369.68,41.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E07 - Chasing the Devil's Tail x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,796.7,358.5,45.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E08 - The Brothers That Care Forgot x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,832.45,355.9,42.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E09 - The Map of Moments x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,829.61,385.98,46.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E10 - Gonna Set Your Flag on Fire x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,716.65,319.37,44.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E11 - Brotherhood of the Damned x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,845.35,371.63,44.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E12 - Sanctuary x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,829.89,342.37,41.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E13 - The Devil Is Damned x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,892.6,404.02,45.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),"The Originals - S02E14 - I Love You, Goodbye x265 AC3 HDTV-1080p ZMNT - [EHX].mkv",847.52,353.94,41.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E15 - They All Asked for You x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,873.45,389.9,44.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E16 - Save My Soul x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,760.23,334.0,43.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E17 - Exquisite Corpse x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,989.11,401.99,40.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E18 - Night Has a Thousand Eyes x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,856.52,361.05,42.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E19 - When the Levee Breaks x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,836.11,377.98,45.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E20 - City Beneath the Sea x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,929.47,396.96,42.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E21 - Fire with Fire x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,936.37,405.98,43.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S02E22 - Ashes to Ashes x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,1006.53,396.97,39.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E01 - For the Next Millennium x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,813.36,364.96,44.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E02 - You Hung the Moon x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,776.94,352.22,45.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E03 - I’ll See You in Hell or New Orleans x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,763.23,359.36,47.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E04 - A Walk on the Wild Side x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,806.79,379.9,47.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E05 - The Axeman's Letter x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,659.81,315.62,47.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E06 - Beautiful Mistake x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,762.0,332.1,43.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E07 - Out of the Easy x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,728.96,326.02,44.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E08 - The Other Girl in New Orleans x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,685.65,296.55,43.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E09 - Savior x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,815.12,371.72,45.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E10 - A Ghost Along the Mississippi x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,751.77,325.19,43.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E11 - Wild at Heart x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,689.62,311.65,45.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E12 - Dead Angels x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,729.53,305.08,41.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E13 - Heart Shaped Box x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,810.25,343.16,42.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E14 - A Streetcar Named Desire (2) x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,635.07,281.71,44.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E15 - An Old Friend Calls x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,675.27,287.44,42.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E16 - Alone with Everybody x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,769.2,337.68,43.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E17 - Behind the Black Horizon x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,814.22,357.81,43.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E18 - The Devil Comes Here and Sighs x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,743.43,333.78,44.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E19 - No More Heartbreaks x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,797.62,328.96,41.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E20 - Where Nothing Stays Buried x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,782.43,329.69,42.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),"The Originals - S03E21 - Give 'Em Hell, Kid x265 AC3 HDTV-1080p ZMNT - [EHX].mkv",835.96,330.93,39.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S03E22 - The Bloody Crown x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,734.55,334.26,45.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E01 - Gather Up the Killers x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,931.37,342.6,36.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E02 - No Quarter x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,1107.13,381.65,34.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E03 - Haunter of Ruins x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,1084.11,361.78,33.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E04 - Keepers of the House x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,995.0,345.39,34.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E05 - I Hear You Knocking x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,1019.88,380.65,37.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E06 - Bag of Cobras x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,809.92,288.01,35.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E07 - High Water and a Devil's Daughter x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,871.03,325.66,37.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E08 - Voodoo in My Blood x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,759.91,295.91,38.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E09 - Queen Death x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,924.05,327.8,35.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E10 - Phantomesque x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,880.79,329.05,37.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E11 - A Spirit Here That Won't Be Broken x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,948.22,336.63,35.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E12 - Voodoo Child x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,767.88,294.98,38.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Originals (2013),The Originals - S04E13 - The Feast of All Sinners x265 AC3 HDTV-1080p ZMNT - [EHX].mkv,836.05,312.72,37.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E01 - Coming 'Round the Mountain (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1834.17,608.26,33.2,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E02 - Promises to Keep (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1788.0,512.82,28.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E03 - People Who Died (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1835.95,538.88,29.4,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E04 - Sins of Omission (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1752.73,425.46,24.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E05 - Damned (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1794.29,431.97,24.1,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E06 - #081693 (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1656.36,523.86,31.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E07 - My Way (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1787.78,498.06,27.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E08 - Belleville (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1454.79,414.58,28.5,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E09 - Teeth and Tissue (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1579.02,466.85,29.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown (2021) - S04E10 - Belly of the Beast (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1664.43,522.79,31.4,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E01 - The Mayor of Kingstown x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2795.82,743.57,26.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E02 - The End Begins x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2118.66,557.79,26.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E03 - Simply Murder x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2320.79,689.49,29.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E04 - The Price x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,1971.54,563.48,28.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E05 - Orion x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,1995.97,551.8,27.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E06 - Every Feather x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2144.15,594.42,27.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E07 - Along Came a Spider x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2409.16,628.68,26.1,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E08 - The Devil is Us x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2334.15,744.89,31.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E09 - The Lie of the Truth x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,1990.94,596.63,30.0,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S01E10 - This Piece of My Soul x265 EAC3 Bluray-1080p Ghost - [EHX].mkv,2151.7,724.44,33.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E01 - Never Missed a Pigeon x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1652.67,593.59,35.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E02 - Staring at the Devil x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1458.31,435.08,29.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E03 - Five at Five x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1166.34,371.93,31.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E04 - The Pool x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1231.43,403.92,32.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E05 - Kill Box x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1235.54,364.38,29.5,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E06 - Left With the Nose x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1186.59,322.55,27.2,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E07 - Drones x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1068.3,329.62,30.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E08 - Santa Jesus x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1479.87,433.16,29.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E09 - Peace in the Valley x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1173.13,343.62,29.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S02E10 - Little Green Ant x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1474.67,308.44,20.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E01 - Soldier's Heart x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1708.27,517.81,30.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E02 - Guts x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1337.44,356.23,26.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E03 - Barbarians at the Gate x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1259.31,384.99,30.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E04 - Rag Doll x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1272.69,353.19,27.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E05 - Iris x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1487.2,358.16,24.1,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E06 - Ecotone x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1195.73,331.25,27.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E07 - Marya Was Here x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1373.67,354.19,25.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E08 - Captain of the Sh-t out of Luck x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1443.89,382.38,26.5,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E09 - Home on the Range x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,1807.17,421.05,23.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Mayor of Kingstown - S03E10 - Comeuppance x265 EAC3 WEBDL-1080p Ghost - [EHX].mkv,2018.98,488.21,24.2,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Behind the Story.mkv,2302.5,819.17,35.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Cast Favorite Scenes.mkv,165.13,72.29,43.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),People of Kingstown.mkv,98.87,32.71,33.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Mayor of Kingstown (2021),Zero Sum Game꞉ The Finale.mkv,416.46,198.23,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E01 - 'Til Death Do Us Part (1080p BluRay x265 Ghost) - [EHX].mkv,803.99,564.86,70.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E02 - A High Bar (1080p BluRay x265 Ghost) - [EHX].mkv,803.95,477.12,59.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E03 - So You Need a Crew? (1080p BluRay x265 Ghost) - [EHX].mkv,803.48,534.11,66.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E04 - Finding Mr. Right (1080p BluRay x265 Ghost) - [EHX].mkv,774.3,431.71,55.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E05 - Being Harley Quinn (1080p BluRay x265 Ghost) - [EHX].mkv,803.53,490.21,61.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,"Harley Quinn (2019) - S01E06 - You're a Damn Good Cop, Jim Gordon (1080p BluRay x265 Ghost) - [EHX].mkv",803.63,433.08,53.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E07 - The Line (1080p BluRay x265 Ghost) - [EHX].mkv,803.99,469.51,58.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E08 - L.O.D.R.S.V.P (1080p BluRay x265 Ghost) - [EHX].mkv,803.23,481.86,60.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E09 - A Seat at the Table (1080p BluRay x265 Ghost) - [EHX].mkv,803.76,449.49,55.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E10 - Bensonhurst (1080p BluRay x265 Ghost) - [EHX].mkv,803.33,443.04,55.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E11 - Harley Quinn Highway (1080p BluRay x265 Ghost) - [EHX].mkv,802.69,539.05,67.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E12 - Devil's Snare (1080p BluRay x265 Ghost) - [EHX].mkv,802.69,534.32,66.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S01E13 - The Final Joke (1080p BluRay x265 Ghost) - [EHX].mkv,802.34,478.3,59.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E01 - New Gotham (1080p BluRay x265 Ghost) - [EHX].mkv,802.81,492.43,61.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E02 - Riddle U (1080p BluRay x265 Ghost) - [EHX].mkv,803.16,495.87,61.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E03 - Catwoman (1080p BluRay x265 Ghost) - [EHX].mkv,804.51,458.38,57.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E04 - Thawing Hearts (1080p BluRay x265 Ghost) - [EHX].mkv,803.41,447.73,55.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E05 - Batman's Back Man (1080p BluRay x265 Ghost) - [EHX].mkv,802.97,439.21,54.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E06 - All the Best Inmates Have Daddy Issues (1080p BluRay x265 Ghost) - [EHX].mkv,803.21,489.42,60.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E07 - There's No Place to Go But Down (1080p BluRay x265 Ghost) - [EHX].mkv,803.2,489.22,60.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E08 - Inner (Para) Demons (1080p BluRay x265 Ghost) - [EHX].mkv,803.68,489.95,61.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E09 - Bachelorette (1080p BluRay x265 Ghost) - [EHX].mkv,803.78,496.96,61.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E10 - Dye Hard (1080p BluRay x265 Ghost) - [EHX].mkv,802.7,494.12,61.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E11 - A Fight Worth Fighting For (1080p BluRay x265 Ghost) - [EHX].mkv,803.35,457.01,56.9,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,Harley Quinn (2019) - S02E12 - Lovers' Quarrel (1080p BluRay x265 Ghost) - [EHX].mkv,802.45,489.44,61.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Harley Quinn,"Harley Quinn (2019) - S02E13 - Something Borrowed, Something Green (1080p BluRay x265 Ghost) - [EHX].mkv",803.68,496.56,61.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E01 - One Ring Don't Make a Dynasty x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,4664.08,1446.42,31.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E02 - The Magic Is Back x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,3711.58,1178.77,31.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E03 - The Second Coming h264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,3467.93,1073.03,30.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E04 - The New World x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,4108.6,1280.27,31.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E05 - The Hamburger Hamlet x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,3737.86,1208.95,32.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E06 - 'beat L.A.' x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,3729.48,1169.87,31.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Winning Time - The Rise of the Lakers Dynasty (2022),Winning Time - The Rise of the Lakers Dynasty - S02E07 - What Is and What Should Never Be x264 EAC3 Atmos WEBDL-1080p NTb - [EHX].mkv,4867.59,1576.8,32.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
movie,N/A,Scott Pilgrim vs. the World (2010) x265 AAC 5.1 Bluray-1080p afm72 - [EHX].mkv,5104.23,2494.68,48.9,1920x1040,1920x1040,5,28,CQ
|
||||||
|
movie,N/A,La La Land (2016) x265 AAC 7.1 Bluray-1080p Tigole - [EHX].mkv,5066.96,2055.78,40.6,1920x754,1920x754,2,28,CQ
|
||||||
|
movie,N/A,Pacific Rim (2013) x264 DTS 5.1 Bluray-1080p 3Li - [EHX].mkv,11307.89,4143.41,36.6,1920x1080,1920x1080,2,32,CQ
|
||||||
|
movie,N/A,Deadpool & Wolverine (2024) x265 AC3 5.1 Bluray-1080p Radarr - [EHX].mkv,3989.24,1811.24,45.4,1920x800,1920x800,2,28,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E01 - Part One x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2239.24,496.66,22.2,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E02 - Part Two x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2011.0,391.54,19.5,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E03 - Part Three x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1754.75,369.66,21.1,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E04 - Part Four x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1877.7,322.6,17.2,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E05 - Part Five x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1933.03,418.72,21.7,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E06 - Part Six x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2198.91,365.38,16.6,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E07 - Part Seven x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1781.45,305.34,17.1,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E08 - Part Eight x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1852.37,309.85,16.7,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Masters of the Air (2024),Masters of the Air - S01E09 - Part Nine x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2797.17,654.05,23.4,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland.S10E01.1080p.WEB-DL-[Feranki1980] - [EHX].mkv,740.61,537.6,72.6,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Shetland,Shetland.S10E02.1080p.iP.WEB-DL.AAC2.0.H.264-RAWR-[Feranki1980] - [EHX].mkv,749.42,519.69,69.3,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Shetland,Shetland.S10E03.1080p.iP.WEB-DL.AAC2.0.H.264-RAWR-[Feranki1980] - [EHX].mkv,747.15,550.36,73.7,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Shetland,Shetland.S10E04.1080p.iP.WEB-DL.AAC2.0.H.264-RAWR-[Feranki1980] - [EHX].mkv,750.47,467.37,62.3,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Shetland,Shetland.S10E05.1080p.iP.WEB-DL.AAC2.0.H.264-RAWR-[Feranki1980] - [EHX].mkv,749.94,431.02,57.5,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Shetland,Shetland.S10E06.1080p.iP.WEB-DL.AAC2.0.H.264-RAWR-[Feranki1980] - [EHX].mkv,748.93,422.54,56.4,1920x972,1280x720,1,30,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E01 - The Fcking Cop (1080p BluRay x265 Panda) - [EHX].mkv,1663.93,826.84,49.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E02 - Welcome to Pixie Swallow (1080p BluRay x265 Panda) - [EHX].mkv,1604.7,762.57,47.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E03 - Steel City Nightfall (1080p BluRay x265 Panda) - [EHX].mkv,1609.56,710.05,44.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E04 - In the Crimson Halls of Kane Hill (1080p BluRay x265 Panda) - [EHX].mkv,1587.18,720.32,45.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E05 - The Fcking Dead (1080p BluRay x265 Panda) - [EHX].mkv,1593.85,762.82,47.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E06 - Booby Traps (1080p BluRay x265 Panda) - [EHX].mkv,1599.97,794.38,49.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E07 - The Gentleman's Agreement (1080p BluRay x265 Panda) - [EHX].mkv,1594.23,737.61,46.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E08 - A Fistful of Blood (1080p BluRay x265 Panda) - [EHX].mkv,1607.68,800.99,49.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E09 - The Chopsocky Special (1080p BluRay x265 Panda) - [EHX].mkv,1563.03,744.2,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E10 - Scar Tissue (1080p BluRay x265 Panda) - [EHX].mkv,1608.92,763.48,47.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E11 - Rise of the Primo (1080p BluRay x265 Panda) - [EHX].mkv,1610.62,858.93,53.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E12 - Faces of Blood Drive (1080p BluRay x265 Panda) - [EHX].mkv,1586.66,868.54,54.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Blood Drive (2017),Blood Drive (2017) - S01E13 - Finish Line (1080p BluRay x265 Panda) - [EHX].mkv,1609.74,571.79,35.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E01 - One Year Later (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1815.56,591.56,32.6,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E02 - Sagrona Teema (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1590.76,530.54,33.4,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E03 - Harvest (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1896.15,741.79,39.1,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E04 - Ever Been to Ghorman (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1931.59,504.66,26.1,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E05 - I Have Friends Everywhere (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1920.68,529.78,27.6,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E06 - What a Festive Evening (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1944.78,558.89,28.7,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E07 - Messenger (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1564.25,416.44,26.6,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E08 - Who Are You (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1680.24,674.59,40.1,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E09 - Welcome to the Rebellion (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,2085.22,591.13,28.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E10 - Make It Stop (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1720.73,593.4,34.5,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S02E11 - Who Else Knows (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1511.14,398.7,26.4,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),"Star Wars Andor (2022) - S02E12 - Jedha, Kyber, Erso (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv",1634.51,462.31,28.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E01 - Kassa (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1403.69,516.89,36.8,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E02 - That Would Be Me (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1275.08,411.33,32.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E03 - Reckoning (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1442.81,567.72,39.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E04 - Aldhani (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1681.32,577.87,34.4,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E05 - The Axe Forgets (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1547.05,493.15,31.9,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E06 - The Eye (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1814.08,662.95,36.5,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E07 - Announcement (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1798.35,518.47,28.8,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E08 - Narkina 5 (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1908.41,603.93,31.6,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E09 - Nobody's Listening! (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1679.27,518.56,30.9,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E10 - One Way Out (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1532.8,526.31,34.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E11 - Daughter of Ferrix (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1538.09,431.23,28.0,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Andor (2022),Star Wars Andor (2022) - S01E12 - Rix Road (1080p DSNP WEB-DL x265 t3nzin) - [EHX].mkv,1940.1,665.2,34.3,1920x804,1920x804,1,28,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E01 - The Floating-Human-Body-Parts Capital of America x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2143.49,700.34,32.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E02 - A Hundred Bucks Says You Won’t x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1734.18,535.68,30.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E03 - Nobody Said He Was Alvin Einstein x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1921.78,665.32,34.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,"Bad Monkey - S01E04 - Nothing’s Wrong With It, I Just Don’t Need It Anymore x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv",2158.57,681.35,31.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E05 - That Damn Arm Is Back x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1599.9,574.72,35.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,"Bad Monkey - S01E06 - Yo, Would You Tell Ms. Chase I Still Love Her Like Crazy x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv",1760.87,551.26,31.3,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E07 - A Total Cat Person x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1572.91,501.69,31.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E08 - The Russian Mob Is Very Active in Key West x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1622.45,494.85,30.5,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E09 - You Really Don’t Want to Kill This Scrumptious Little Puppy x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1490.04,548.12,36.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Bad Monkey,Bad Monkey - S01E10 - We’re in the Memory-Making Business x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1478.87,565.11,38.2,1920x960,1280x720,1,26,CQ
|
||||||
|
movie,N/A,Project Hail Mary (2026) h265 EAC3 Atmos 5.1 WEBDL-2160p RDNYB - [EHX].mkv,25055.44,3042.63,12.1,3840x2160,1920x1080,1,28,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E02 - Talented & Terrible - Culinary Pageant h264 AAC WEBDL-1080p RAWR - [EHX].mkv,4468.35,1054.7,23.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E03 - Talented & Terrible - The Da Vinci Cook h264 AAC WEBDL-1080p RAWR - [EHX].mkv,4280.04,1023.44,23.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E04 - Talented & Terrible - Flavor Freestyle h264 AAC WEBDL-1080p RAWR - [EHX].mkv,3062.58,751.94,24.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E05 - Talented & Terrible - Big Top Boot Camp h264 AAC WEBDL-1080p RAWR - [EHX].mkv,3079.97,696.2,22.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E06 - Talented & Terrible - Encores and Entrees h264 AAC WEBDL-1080p RAWR - [EHX].mkv,2808.21,735.21,26.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S29E07 - Talented & Terrible - Culinary Curtain Call h264 AAC WEBDL-1080p FREQUENCY - [EHX].mkv,3096.2,666.74,21.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),"Worst Cooks in America - S30E01 - Reality Check - Lights, Camera, Boot Camp h264 AAC WEBDL-1080p FREQUENCY - [EHX].mkv",5823.63,1405.72,24.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S30E02 - Reality Check - Hollywood's Next Culinary Star h264 AAC WEBDL-1080p CBFM - [EHX].mkv,4271.91,1034.9,24.2,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S30E03 - Reality Check - The Worst Lotus x265 EAC3 HDTV-1080p MeGusta - [EHX].mkv,1078.62,976.55,90.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S30E04 - Reality Check - Culinary Outlaws x265 EAC3 HDTV-1080p MeGusta - [EHX].mkv,722.7,656.14,90.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Worst Cooks in America (2010),"Worst Cooks in America - S30E05 - Reality Check - Glitz, Glam and Gourmet h264 EAC3 WEBDL-1080p EDITH - [EHX].mkv",3170.18,750.22,23.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S30E06 - Reality Check - Agents of Flavor h264 EAC3 WEBDL-1080p EDITH - [EHX].mkv,3148.53,750.47,23.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Worst Cooks in America (2010),Worst Cooks in America - S30E07 - Reality Check - Bite Club h264 EAC3 WEBDL-1080p EDITH - [EHX].mkv,3153.19,692.22,22.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E05 - Caitlin, Nick, and Geoff Take You to Church - [EHX].mkv",927.06,461.66,49.8,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E06 - Josh, Anna, and Jiavani Make a Day Rate - [EHX].mkv",1066.9,552.48,51.8,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E07 - Ross, Echo, and Corin Try to Recruit You - [EHX].mkv",968.47,508.98,52.6,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E08 - Jacob, Kurt, and Angela Have Fun with Filters - [EHX].mkv",1133.02,587.73,51.9,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,Make Some Noise - S04E09 - Different Language Office - [EHX].mkv,1245.54,501.08,40.2,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E10 - Anna, Geoff, and Jeremy Act Out Kids' Prompts - [EHX].mkv",1007.84,508.76,50.5,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E11 - Ally, Brennan, and Talia Try to Get Through Lunch - [EHX].mkv",1236.42,554.63,44.9,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E12 - Ben, Lisa, and Colton Have a Party - [EHX].mkv",1405.3,654.99,46.6,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,"Make Some Noise - S04E13 - Jacob, Kimia, and Jeremy Impersonate Each Other - [EHX].mkv",1252.55,603.24,48.2,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,Make Some Noise - S04E14 - Eat an Animal Before It Eats You Show - [EHX].mkv,1020.35,450.22,44.1,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,Make Some Noise - S04E15 - The Noise Boys Hype Each Other Up - [EHX].mkv,1290.93,602.25,46.7,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Make Some Noise,Make Some Noise - S04E16 - Make Some Noise Season 4: Cut For Time - [EHX].mkv,1847.06,871.61,47.2,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E01 - It's a Banksy - [EHX].mkv,585.29,281.93,48.2,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E02 - Two Hours in the Tesla Diner - [EHX].mkv,640.65,315.11,49.2,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E03 - At the Strip Club With Your Dentist - [EHX].mkv,579.55,281.68,48.6,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E04 - In My Feels About the Cold War - [EHX].mkv,566.61,274.53,48.5,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E05 - Give It up for McBean - [EHX].mkv,684.43,354.38,51.8,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Dimension 20's Adventuring Party,Dimension 20's Adventuring Party - S24E06 - Zaeth is a Guided Missle - [EHX].mkv,635.99,315.73,49.6,1920x1080,1920x1080,1,32,CQ
|
||||||
|
tv,Shetland,Shetland - 1x01 - Red Bones (1) - [EHX].mkv,1786.03,355.61,19.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 1x02 - Red Bones (2) - [EHX].mkv,2008.56,395.36,19.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x01 - Raven Black (1) - [EHX].mkv,2438.95,434.27,17.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x02 - Raven Black (2) - [EHX].mkv,2374.69,416.86,17.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x03 - Dead Water (1) - [EHX].mkv,2448.49,549.86,22.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x04 - Dead Water (2) - [EHX].mkv,2267.17,469.62,20.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x05 - Blue Lightning (1) - [EHX].mkv,2242.65,410.37,18.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 2x06 - Blue Lightning (2) - [EHX].mkv,2324.61,424.86,18.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x01 - Episode 1 - [EHX].mkv,2836.64,520.21,18.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x02 - Episode 2 - [EHX].mkv,3016.83,547.02,18.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x03 - Episode 3 - [EHX].mkv,2786.69,495.28,17.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x04 - Episode 4 - [EHX].mkv,2788.17,453.53,16.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x05 - Episode 5 - [EHX].mkv,2721.46,419.41,15.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 3x06 - Episode 6 - [EHX].mkv,2734.36,449.01,16.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x01 - Episode 1 - [EHX].mkv,1847.61,389.46,21.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x02 - Episode 2 - [EHX].mkv,1884.3,398.76,21.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x03 - Episode 3 - [EHX].mkv,2055.46,431.0,21.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x04 - Episode 4 - [EHX].mkv,2563.94,548.04,21.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x05 - Episode 5 - [EHX].mkv,2618.41,529.71,20.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 4x06 - Episode 6 - [EHX].mkv,2551.99,487.53,19.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x01 - Episode 1 - [EHX].mkv,2175.39,447.96,20.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x02 - Episode 2 - [EHX].mkv,1930.68,380.52,19.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x03 - Episode 3 - [EHX].mkv,2231.29,476.87,21.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x04 - Episode 4 - [EHX].mkv,2171.84,384.35,17.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x05 - Episode 5 - [EHX].mkv,2194.03,351.3,16.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 5x06 - Episode 6 - [EHX].mkv,2047.55,329.29,16.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x01 - Episode 1 - [EHX].mkv,1772.15,393.86,22.2,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x02 - Episode 2 - [EHX].mkv,1763.73,381.19,21.6,1920x958,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x03 - Episode 3 - [EHX].mkv,1812.15,378.93,20.9,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x04 - Episode 4 - [EHX].mkv,1895.41,444.11,23.4,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x05 - Episode 5 - [EHX].mkv,1633.78,369.25,22.6,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 6x06 - Episode 6 - [EHX].mkv,1743.38,371.84,21.3,1920x958,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x01 - Episode 1 - [EHX].mkv,2610.02,482.27,18.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x02 - Episode 2 - [EHX].mkv,2247.16,383.55,17.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x03 - Episode 3 - [EHX].mkv,2266.94,383.24,16.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x04 - Episode 4 - [EHX].mkv,2577.64,416.21,16.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x05 - Episode 5 - [EHX].mkv,2397.76,359.82,15.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 7x06 - Episode 6 - [EHX].mkv,2474.1,426.78,17.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x01 - Episode 1 - [EHX].mkv,1824.43,366.91,20.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x02 - Episode 2 - [EHX].mkv,1553.08,313.85,20.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x03 - Episode 3 - [EHX].mkv,1621.35,326.89,20.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x04 - Episode 4 - [EHX].mkv,1495.52,295.7,19.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x05 - Episode 5 - [EHX].mkv,1521.28,298.26,19.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 8x06 - Episode 6 - [EHX].mkv,1454.73,317.37,21.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x01 - Episode 1 - [EHX].mkv,1626.66,350.51,21.5,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x02 - Episode 2 - [EHX].mkv,1626.12,341.97,21.0,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x03 - Episode 3 - [EHX].mkv,1560.74,334.41,21.4,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x04 - Episode 4 - [EHX].mkv,1573.49,327.56,20.8,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x05 - Episode 5 - [EHX].mkv,1479.96,297.96,20.1,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,Shetland,Shetland - 9x06 - Episode 6 - [EHX].mkv,1395.64,302.41,21.7,1920x960,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E01 - Pilot (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,619.43,311.78,50.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E02 - The Aftermath (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,622.99,296.59,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E03 - Blind Date (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,512.97,244.42,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E04 - Jack the Writer (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,569.21,268.55,47.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E05 - Jack-Tor (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,606.78,312.55,51.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E06 - Jack Meets Dennis (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,490.48,232.39,47.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E07 - Tracy Does Conan (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,686.13,302.5,44.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E08 - The Break-Up (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,486.46,244.63,50.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E09 - The Baby Show (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,529.08,259.27,49.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E10 - The Rural Juror (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,607.79,270.47,44.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E11 - The Head and the Hair (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,496.91,235.81,47.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E12 - Black Tie (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,480.02,240.58,50.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E13 - Up All Night (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,528.69,251.67,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E14 - The “C” Word (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,611.65,268.59,43.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E15 - Hard Ball (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,564.51,269.5,47.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E16 - The Source Awards (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,567.92,257.8,45.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E17 - The Fighting Irish (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,514.07,241.25,46.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E18 - Fireworks (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,558.39,275.88,49.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E19 - Corporate Crush (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,557.87,244.85,43.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E20 - Cleveland (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,539.64,252.13,46.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S01E21 - Hiatus (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,605.32,255.01,42.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E01 - Seinfeld Vision (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,568.97,258.66,45.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E02 - Jack Gets in the Game (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,590.69,266.71,45.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E03 - The Collection (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,607.98,257.13,42.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E04 - Rosemary's Baby (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,622.95,269.44,43.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E05 - Greenzo (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,523.51,247.39,47.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E06 - Somebody to Love (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,436.4,216.6,49.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E07 - Cougars (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,573.58,266.53,46.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E08 - Secrets & Lies (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,522.23,241.46,46.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E09 - Episode 209 (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,633.94,295.98,46.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E10 - Episode 210 (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,533.66,253.84,47.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E11 - MILF Island (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,407.13,198.99,48.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E12 - Subway Hero (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,585.17,264.58,45.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E13 - Succession (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,479.66,224.32,46.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E14 - Sandwich Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,494.43,228.96,46.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S02E15 - Cooter (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,463.87,228.42,49.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E01 - Do-Over (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,675.88,279.04,41.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E02 - Believe in the Stars (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,584.34,245.88,42.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E03 - The One with the Cast of Night Court (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,558.44,238.96,42.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E04 - Gavin Volure (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,504.32,215.01,42.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E05 - Reunion (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,512.35,236.64,46.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E06 - Christmas Special (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,617.35,239.32,38.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E07 - Señor Macho Solo (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,542.79,227.47,41.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E08 - Flu Shot (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,494.2,211.13,42.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E09 - Retreat to Move Forward (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,556.74,224.61,40.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E10 - Generalissimo (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,515.93,210.15,40.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E11 - St. Valentine's Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,466.02,179.3,38.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E12 - Larry King (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,457.86,182.84,39.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S03E13 - Goodbye, My Friend (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",474.62,189.23,39.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E14 - The Funcooker (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,515.2,197.72,38.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E15 - The Bubble (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,523.91,202.6,38.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S03E16 - Apollo, Apollo (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",562.72,202.58,36.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E17 - Cutbacks (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,482.13,179.14,37.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E18 - Jackie Jormp-Jomp (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,532.49,193.32,36.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E19 - The Ones (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,536.75,184.12,34.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E20 - The Natural Order (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,576.49,193.6,33.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E21 - Mamma Mia (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,651.76,207.01,31.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S03E22 - Kidney Now! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,659.56,218.94,33.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E01 - Season 4 (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,702.73,262.83,37.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E02 - Into the Crevasse (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,615.33,235.74,38.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E03 - Stone Mountain (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,497.09,199.93,40.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E04 - Audition Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,581.58,235.13,40.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E05 - The Problem Solvers (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,482.28,181.28,37.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E06 - Sun Tea (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,611.09,212.09,34.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E07 - Dealbreakers Talk Show #0001 (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,490.67,180.0,36.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E08 - Secret Santa (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,501.55,190.51,38.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E09 - Klaus and Greta (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,462.47,165.2,35.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E10 - Black Light Attack! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,464.96,181.33,39.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E11 - Winter Madness (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,523.27,188.52,36.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E12 - Verna (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,515.65,165.74,32.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E13 - Anna Howard Shaw Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,515.26,176.9,34.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E14 - Future Husband (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,502.52,164.11,32.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S04E15 - Don Geiss, America, and Hope (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",536.92,153.04,28.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E16 - Floyd (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,539.01,152.82,28.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E17 - Lee Marvin vs. Derek Jeter (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,635.3,169.7,26.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E18 - Khonani (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,523.96,154.83,29.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E19 - Argus (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,528.38,150.83,28.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E20 - The Moms (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,679.28,175.61,25.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E21 - Emmanuelle Goes to Dinosaur Land (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,726.07,177.69,24.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S04E22 - I Do Do (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,725.29,184.12,25.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E01 - The Fabian Strategy (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,543.68,175.34,32.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S05E02 - When It Rains, It Pours (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",667.57,218.66,32.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E03 - Let's Stay Together (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,518.81,171.54,33.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E04 - Live Show (East Coast) (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,1068.95,453.0,42.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E05 - Reaganing (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,631.88,211.82,33.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E06 - Gentleman's Intermission (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,462.05,152.43,33.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E07 - Brooklyn Without Limits (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,487.01,157.02,32.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E08 - College (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,522.02,171.79,32.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E09 - Chain Reaction of Mental Anguish (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,448.51,142.09,31.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E10 - Christmas Attack Zone (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,504.04,148.92,29.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E11 - Mrs. Donaghy (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,537.33,160.1,29.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E12 - Operation Righteous Cowboy Lightning (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,549.14,166.23,30.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E13 - Que Sorpresa! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,553.04,161.53,29.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E14 - Double-Edged Sword (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,486.71,144.05,29.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E15 - It's Never Too Late for Now (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,641.65,182.79,28.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E16 - TGS Hates Women (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,579.59,169.4,29.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E17 - Queen of Jordan (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,734.45,289.83,39.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E18 - Plan B (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,532.16,155.79,29.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E19 - I Heart Connecticut (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,574.89,167.63,29.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E20 - 100 (1) (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,676.41,209.56,31.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E21 - 100 (2) (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,508.25,149.64,29.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E22 - Everything Sunny All the Time Always (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,630.52,189.99,30.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S05E23 - Respawn (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,692.59,198.43,28.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E01 - Dance Like Nobody's Watching (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,670.36,246.07,36.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E02 - Idiots are People Two! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,628.17,241.75,38.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E03 - Idiots are People Three! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,553.49,214.75,38.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E04 - The Ballad of Kenneth Parcell (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,670.39,244.21,36.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E05 - Today You Are a Man (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,793.58,257.54,32.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S06E06-E07 - Hey, Baby, What's Wrong (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",1384.64,487.86,35.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E08 - The Tuxedo Begins (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,711.17,254.63,35.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E09 - Leap Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,803.59,280.91,35.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E10 - Alexis Goodlooking and the Case of the Missing Whisky (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,701.69,245.91,35.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E11 - Standards and Practices (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,635.65,232.3,36.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E12 - St. Patrick's Day (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,717.66,253.56,35.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E13 - Grandmentor (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,597.52,227.33,38.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E14 - Kidnapped by Danger (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,709.92,253.58,35.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E15 - The Shower Principle (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,713.21,256.55,36.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E16 - Nothing Left to Lose (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,832.17,287.65,34.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E17 - Meet the Woggels! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,710.81,263.97,37.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E18 - Murphy Brown Lied to Us (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,590.18,225.91,38.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E19 - Live from Studio 6H (East Coast) (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,1130.2,497.92,44.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E20 - Queen of Jordan II Mystery of the Phantom Pooper (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,739.62,346.32,46.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E21 - The Return of Avery Jessup (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,614.72,241.11,39.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S06E22 - What Will Happen to the Gang Next Year (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,597.94,247.0,41.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E01 - The Beginning of the End (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,582.72,244.52,42.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E02 - Governor Dunston (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,619.59,260.05,42.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E03 - Stride of Pride (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,671.13,264.61,39.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E04 - Unwindulax (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,830.65,283.76,34.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E05 - There's No I in America (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,452.37,201.55,44.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E06 - Aunt Phatso vs. Jack Donaghy (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,603.79,235.89,39.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),"30 Rock (2006) - S07E07 - Mazel Tov, Dummies! (1080p AMZN WEBRip x265 Silence) - [EHX].mkv",628.2,254.34,40.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E08 - My Whole Life is Thunder (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,573.33,233.6,40.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E09 - Game Over (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,541.5,215.68,39.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E10 - Florida (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,803.14,254.29,31.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E11 - A Goon's Deed in a Weary World (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,548.41,235.67,43.0,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,30 Rock (2006),30 Rock (2006) - S07E12-E13 - Hogcock! and Last Lunch (1080p AMZN WEBRip x265 Silence) - [EHX].mkv,1337.22,495.83,37.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E01 - Pilot h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,388.66,294.39,75.7,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E02 - Lawnmower Dog h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,428.75,330.44,77.1,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E03 - Anatomy Park h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,496.8,358.51,72.2,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E04 - M. Night Shaym-Aliens! h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,625.93,370.1,59.1,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E05 - Meeseeks and Destroy h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,376.17,297.14,79.0,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E06 - Rick Potion #9 h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,428.03,336.61,78.6,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E07 - Raising Gazorpazorp h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,428.81,305.99,71.4,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E09 - Something Ricked This Way Comes h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,381.91,285.31,74.7,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E10 - Close Rick-Counters of the Rick Kind h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,563.59,393.07,69.7,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S01E11 - Ricksy Business h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,482.21,348.21,72.2,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E01 - A Rickle in Time h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,738.83,467.74,63.3,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E02 - Mortynight Run h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,664.13,440.28,66.3,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E03 - Auto Erotic Assimilation h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,473.12,332.51,70.3,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E04 - Total Rickall h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,522.01,371.03,71.1,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E05 - Get Schwifty h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,449.3,322.98,71.9,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E06 - The Ricks Must Be Crazy h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,520.87,368.41,70.7,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E07 - Big Trouble in Little Sanchez h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,410.98,309.36,75.3,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E08 - Interdimensional Cable 2 - Tempting Fate h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,398.73,308.1,77.3,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E09 - Look Who's Purging Now h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,357.11,264.86,74.2,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S02E10 - The Wedding Squanchers h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,445.56,307.05,68.9,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E01 - The Rickshank Rickdemption h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,473.36,352.96,74.6,1920x1080,1920x1080,3,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E02 - Rickmancing the Stone h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,347.09,265.74,76.6,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E03 - Pickle Rick h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,372.74,272.6,73.1,1920x1080,1920x1080,4,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E04 - Vindicators 3 - The Return of Worldender h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,383.73,295.68,77.1,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E05 - The Whirly Dirly Conspiracy h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,449.76,337.6,75.1,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E06 - Rest and Ricklaxation h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,362.78,280.89,77.4,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E07 - The Ricklantis Mixup h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,351.59,271.39,77.2,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E08 - Morty's Mind Blowers h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,364.09,280.28,77.0,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E09 - The ABC's of Beth h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,319.93,255.32,79.8,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S03E10 - The Rickchurian Mortydate h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,335.26,257.54,76.8,1920x1080,1920x1080,2,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E01 - Edge of Tomorty - Rick Die Rickpeat h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,370.99,297.11,80.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E02 - The Old Man and the Seat h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,284.37,229.56,80.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E03 - One Crew Over the Crewcoo's Morty h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,303.42,240.43,79.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E04 - Claw and Hoarder - Special Ricktim's Morty h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,329.97,263.37,79.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E05 - Rattlestar Ricklactica h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,295.87,245.8,83.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E06 - Never Ricking Morty h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,348.97,276.02,79.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E07 - Promortyus h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,397.76,303.08,76.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E08 - The Vat of Acid Episode h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,313.57,256.2,81.7,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E09 - Childrick of Mort h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,436.34,336.87,77.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S04E10 - Star Mort - Rickturn of the Jerri h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,339.49,270.91,79.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E01 - Mort Dinner Rick Andre h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,369.6,302.91,82.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E02 - Mortyplicity h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,355.2,288.35,81.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E03 - A Rickconvenient Mort h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,539.75,380.64,70.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E04 - Rickdependence Spray h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,303.01,247.26,81.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E05 - Amortycan Grickfitti h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,342.24,268.19,78.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E06 - Rick & Morty's Thanksploitation Spectacular h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,429.56,338.68,78.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E07 - Gotron Jerrysis Rickvangelion h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,361.95,284.13,78.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E08 - Rickternal Friendshine of the Spotless Mort h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,341.13,274.1,80.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E09 - Forgetting Sarick Mortshall h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,319.26,254.03,79.6,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S05E10 - Rickmurai Jack h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,420.75,318.91,75.8,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E01 - Solaricks h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,312.7,244.74,78.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E02 - Rick - A Mort Well Lived h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,304.22,231.31,76.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E03 - Bethic Twinstinct h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,219.22,185.28,84.5,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E04 - Night Family h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,484.49,257.86,53.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E05 - Final DeSmithation h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,378.16,287.36,76.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E06 - JuRicksic Mort h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,301.06,241.73,80.3,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E07 - Full Meta Jackrick h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,495.23,347.25,70.1,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E08 - Analyze Piss h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,326.54,262.67,80.4,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E09 - A Rick in King Mortur's Mort h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,338.94,258.22,76.2,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S06E10 - Ricktional Mortpoon's Rickmas Mortcation h265 AAC Bluray-1080p SEPH1 - [EHX].mkv,258.4,214.42,83.0,1920x1080,1920x1080,1,28,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E01 - [EHX].mkv,639.33,352.41,55.1,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E02 - [EHX].mkv,677.88,343.25,50.6,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E03 - [EHX].mkv,638.63,298.37,46.7,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E04 - [EHX].mkv,631.08,281.44,44.6,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E05 - [EHX].mkv,641.12,441.61,68.9,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E06 - [EHX].mkv,670.36,307.97,45.9,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E07 - [EHX].mkv,640.18,352.19,55.0,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E08 - [EHX].mkv,640.49,429.79,67.1,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E09 - [EHX].mkv,637.41,361.63,56.7,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S07E10 - [EHX].mkv,700.58,329.79,47.1,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E01 - [EHX].mkv,878.85,343.22,39.1,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E02 - [EHX].mkv,783.22,404.17,51.6,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E03 - [EHX].mkv,792.25,361.16,45.6,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E04 - [EHX].mkv,782.85,386.15,49.3,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E05 - [EHX].mkv,755.47,406.12,53.8,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E06 - [EHX].mkv,758.77,378.57,49.9,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E07 - [EHX].mkv,839.63,354.81,42.3,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E08 - [EHX].mkv,816.0,299.14,36.7,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E09 - [EHX].mkv,837.89,335.35,40.0,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,Rick and Morty,Rick and Morty - S08E10 - [EHX].mkv,872.92,347.55,39.8,1920x1080,1920x1080,6,32,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E01 - Never the New (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,2355.56,700.59,29.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E02 - Money Isn't Everything (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1342.48,406.31,30.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E03 - Face the Music (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1619.88,401.44,24.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E01.FreeCommerce.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1439.26,340.69,23.7,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E02.Eye.Contact.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1142.8,260.67,22.8,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E03.Risk.Assessment.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1060.32,251.35,23.7,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E04.Escape.Velocity.Protocol.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1027.77,266.28,25.9,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E05.Rogue.War.Tracker.Infinite.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1029.85,245.2,23.8,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E06.Command.Feed.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1056.52,246.88,23.4,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E07.Complementary.Species.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1378.03,311.81,22.6,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E08.Foreign.Object.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1121.12,269.56,24.0,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E09.All.Systems.Red.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1783.14,383.7,21.5,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,Murderbot (2025),Murderbot.S01E10.The.Perimeter.2160p.10bit.ATVP.WEB-DL.DDP5.1.HEVC-Vyndros - [EHX].mkv,1517.16,358.92,23.7,3840x1606,1920x1080,1,28,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E01 - Who is in Charge Here?(1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1647.28,372.02,22.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E02 - What the Papers Say (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1680.97,366.48,21.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E03 - Love is Never Easy (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1831.99,398.47,21.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E04 - Marriage is a Gamble (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1857.12,444.66,23.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E05 - A Different World (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1690.86,414.97,24.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E06 - If You Want to Cook an Omelette (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1873.59,341.94,18.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E07 - Ex-Communicated (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1818.67,336.2,18.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S03E08 - My Mind is Made Up (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,2126.51,499.37,23.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E04 - A Long Ladder (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1659.63,406.14,24.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E05 - Charity Has Two Functions (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1395.33,369.05,26.4,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E06 - Heads Have Rolled for Less (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1578.11,428.13,27.1,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E07 - Irresistible Change (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1347.89,346.94,25.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E08 - Tucked Up in Newport (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1450.68,443.96,30.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S01E09 - Let the Tournament Begin (1080p HMAX WEB-DL x265 Ghost) - [EHX].mkv,1795.71,490.98,27.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E01 - You Don't Even Like Opera (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1849.4,479.91,25.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E02 - Some Sort of Trick (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1681.46,418.24,24.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E03 - Head to Head (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1753.25,381.43,21.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E04 - His Grace the Duke (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1627.35,354.66,21.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E05 - Close Enough to Touch (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1803.63,407.18,22.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E06 - Warning Shots (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1735.19,397.37,22.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E07 - Wonders Never Cease (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1657.78,328.61,19.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Gilded Age (2022) - S02E08 - In Terms of Winning and Losing (1080p AMZN WEB-DL x265 Ghost) - [EHX].mkv,1815.74,357.34,19.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Behind the Gilded Curtain.mkv,51.96,28.16,54.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - Ada Brook.mkv,22.94,8.88,38.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - Agnes Van Rhijn.mkv,29.61,14.94,50.5,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - Bertha Russell.mkv,25.6,14.48,56.6,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - George Russell.mkv,26.56,10.29,38.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - Marian Brook.mkv,24.26,13.06,53.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Recap - Peggy Scott.mkv,18.42,7.78,42.2,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Character Superlatives.mkv,38.87,17.08,43.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Season 2 - Testing the Cast on 1800s Etiquette.mkv,66.61,32.43,48.7,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Behind the Scenes.mkv,46.27,27.46,59.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Meet the Russell Household.mkv,145.78,63.12,43.3,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Meet the Van Rhijn Household.mkv,210.26,83.95,39.9,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,The Black Elite of New York.mkv,83.86,39.24,46.8,1920x1080,1280x720,1,26,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E01 - Pilot h264 EAC3 WEBDL-1080p Cinefeel - [EHX].mkv,1617.57,281.4,17.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E02 - Hog Riders h264 EAC3 WEBDL-1080p Cine - [EHX].mkv,1306.41,266.15,20.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E03 - Sam the Man h264 EAC3 WEBDL-1080p Cin - [EHX].mkv,1353.1,231.54,17.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E04 - Devereux Wigs h264 EAC3 WEBDL-1080p C - [EHX].mkv,1226.19,236.65,19.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E05 - Happy Birthday Mr. Duvet h264 EAC3 WEBDL-1080p Cinefeel - [EHX].mkv,1693.07,281.46,16.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E06 - 3rd Floor h264 EAC3 WEBDL-1080p Cinef - [EHX].mkv,1397.62,280.39,20.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E07 - Smilin' Jack h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,2149.76,299.81,13.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E08 - Dream Cruise h264 EAC3 WEBDL-1080p Ci - [EHX].mkv,1165.75,264.61,22.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E09 - Husky Boys h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1870.09,237.62,12.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S01E10 - Quick Rick Mahorn in Dearborn h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1811.98,268.63,14.8,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E01 - April in the D h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1711.3,271.81,15.9,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E02 - Jefferson Porger h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1799.67,276.48,15.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E03 - Duvet Family Reunion h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1809.03,354.4,19.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E04 - Trevor h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1971.51,296.49,15.0,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E05 - Farmer Zack h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1794.2,275.27,15.3,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E06 - Mort Crim h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1889.63,258.37,13.7,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E07 - Lois h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1713.12,282.41,16.5,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E08 - Hark Motors h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1636.59,255.79,15.6,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E09 - Little Caesars h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1892.36,266.37,14.1,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,Detroiters (2017),Detroiters - S02E10 - Royals h264 EAC3 WEBDL-1080p DiMEPiECE - [EHX].mkv,1941.62,259.28,13.4,1920x1080,1280x720,1,30,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E01 - Episode 1 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1982.73,441.85,22.3,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E02 - Episode 2 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1841.38,378.38,20.5,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E03 - Episode 3 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1751.82,343.95,19.6,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E04 - Episode 4 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1721.93,326.18,18.9,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E05 - Episode 5 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1713.0,336.91,19.7,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E06 - Episode 6 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1721.37,308.46,17.9,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E07 - Episode 7 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1595.21,298.66,18.7,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E08 - Episode 8 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1662.14,470.52,28.3,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E09 - Episode 9 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,1648.34,416.46,25.3,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Behind the Scenes.mkv,27.46,24.94,90.8,1280x720,1280x720,1,26,CQ
|
||||||
|
tv,The Gilded Age,Meet the Russell Household.mkv,63.12,58.41,92.5,1280x720,1280x720,1,26,CQ
|
||||||
|
tv,The Day of the Jackal (2024),The Day of the Jackal - S01E10 - Episode 10 x265 EAC3 Atmos WEBDL-1080p Ghost - [EHX].mkv,2149.17,438.33,20.4,1920x804,1280x720,1,26,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E01 - God U x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,2051.12,823.55,40.2,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E02 - First Day x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1713.19,660.32,38.5,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E03 - #ThinkBrink x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1801.66,678.1,37.6,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E04 - The Whole Truth x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1637.82,573.9,35.0,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E05 - Welcome to the Monster Club x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1429.56,540.6,37.8,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E06 - Jumanji x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1407.65,549.23,39.0,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E07 - Sick x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1691.08,685.68,40.5,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,Gen V (2023),Gen V - S01E08 - Guardians of Godolkin x265 EAC3 WEBDL-1080p Silence - [EHX].mkv,1356.4,554.18,40.9,1920x800,1920x800,1,28,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E01 - A Night of Cards x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,2793.09,421.9,15.1,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E02 - Step Into the Sun x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,2814.92,473.91,16.8,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E03 - Magnetism x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,3866.87,642.06,16.6,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E04 - The Creed x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,3543.99,588.84,16.6,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E05 - Horizon x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,3313.0,546.04,16.5,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,The Eternaut,The Eternaut - S01E06 - Cold Tomato Juice x264 EAC3 Atmos WEBDL-1080p EDITH - [EHX].mkv,4224.26,734.41,17.4,1920x1080,1280x720,2,30,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E01 - The Gospel of Kenny Sharp x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,932.27,423.16,45.4,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E02 - Trial and Error x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,678.93,313.19,46.1,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E03 - Two Doors x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,429.54,189.7,44.2,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E04 - A Long Road Home x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,656.74,312.79,47.6,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),"Government Cheese - S01E05 - Father Facts, Figures, and Failures x265 AC3 HDTV-1080p ELiTE - [EHX].mkv",887.0,335.28,37.8,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E06 - Parable of Drawing in the Net x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,683.34,328.12,48.0,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E07 - The Woman on the Roof x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,617.7,270.56,43.8,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E08 - An Evening with Abraham Cohen x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,599.14,261.67,43.7,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E09 - R&D x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,573.82,241.84,42.1,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Government Cheese (2025),Government Cheese - S01E10 - St. Hampton x265 AC3 HDTV-1080p ELiTE - [EHX].mkv,733.06,294.47,40.2,1920x1038,1280x720,1,26,CQ
|
||||||
|
tv,Adventuring Academy,Adventuring Academy - S07E01 - Bandaid on a Bowling Ball (with Vic Michaelis) - [EHX].mkv,2625.24,1161.67,44.3,1920x1080,1920x1080,1,32,CQ
|
||||||
|
movie,N/A,Boy Kills World 2023 2160p AMZN WEB-DL DDP5 1 H 265-BYNDR - [EHX].mkv,12911.95,1926.43,14.9,3840x1600,1920x1080,1,32,CQ
|
||||||
|
|||||||
|
Can't render this file because it has a wrong number of fields in line 14.
|
@ -207,7 +207,34 @@ def get_audio_streams(input_file: Path):
|
|||||||
return streams
|
return streams
|
||||||
|
|
||||||
|
|
||||||
def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, is_1080_class: bool) -> tuple:
|
def find_nearest_bitrate(source_bitrate_kbps: int, candidate_bitrates: list, threshold_kbs: int = 10) -> int:
|
||||||
|
"""
|
||||||
|
Check if source bitrate is within threshold of a standard bitrate.
|
||||||
|
If within -threshold kbs of a standard bitrate, return that standard bitrate.
|
||||||
|
Otherwise return 0 (meaning copy the source).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source_bitrate_kbps: Source bitrate in kbps
|
||||||
|
candidate_bitrates: List of standard bitrates in bits/sec (e.g., [128000, 192000])
|
||||||
|
threshold_kbs: Tolerance in kbps (default 10)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Standard bitrate (in bits/sec) if within threshold, else 0
|
||||||
|
"""
|
||||||
|
source_bps = source_bitrate_kbps * 1000
|
||||||
|
threshold_bps = threshold_kbs * 1000
|
||||||
|
|
||||||
|
for candidate_bps in candidate_bitrates:
|
||||||
|
candidate_kbps = candidate_bps / 1000
|
||||||
|
# Check if source is within -threshold to +0 of the candidate
|
||||||
|
if source_bps >= (candidate_bps - threshold_bps) and source_bps <= candidate_bps:
|
||||||
|
logger.debug(f"Source bitrate {source_bitrate_kbps}kbps is within -{threshold_kbs}kbps of target {candidate_kbps:.0f}kbps - using standard bitrate")
|
||||||
|
return candidate_bps
|
||||||
|
|
||||||
|
return 0 # No match within threshold
|
||||||
|
|
||||||
|
|
||||||
|
def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, is_1080_class: bool, is_commentary: bool = False) -> tuple:
|
||||||
"""
|
"""
|
||||||
Choose audio codec and bitrate based on channel count, detected bitrate, and resolution.
|
Choose audio codec and bitrate based on channel count, detected bitrate, and resolution.
|
||||||
|
|
||||||
@ -216,46 +243,79 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
|||||||
- target_bitrate_bps: target bitrate in bits/sec (0 if using "copy")
|
- target_bitrate_bps: target bitrate in bits/sec (0 if using "copy")
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
Commentary tracks: Always use "low" stereo bitrate (e.g., 128kbps)
|
||||||
|
|
||||||
Stereo + 1080p:
|
Stereo + 1080p:
|
||||||
- Above 192k → encode to 192k with AAC
|
- Above 192k → encode to 192k with AAC
|
||||||
- At/below 192k → preserve (copy)
|
- At/below 192k → check if within -10kbps of standard bitrate, else preserve (copy)
|
||||||
|
|
||||||
Stereo + 720p:
|
Stereo + 720p:
|
||||||
- Above 160k → encode to 160k with AAC
|
- Above 160k → encode to 160k with AAC
|
||||||
- At/below 160k → preserve (copy)
|
- At/below 160k → check if within -10kbps of standard bitrate, else preserve (copy)
|
||||||
|
|
||||||
Multi-channel (5.1+):
|
Multi-channel (5.1+):
|
||||||
- Below minimum threshold → preserve original (copy)
|
- Below minimum threshold → check if within -10kbps of standard bitrate, else preserve (copy)
|
||||||
- Low to medium → use EAC3 codec
|
- Low to medium → use EAC3 codec
|
||||||
"""
|
"""
|
||||||
|
# Commentary tracks always use low stereo bitrate
|
||||||
|
if is_commentary:
|
||||||
|
low_br = audio_config["stereo"]["low"]
|
||||||
|
return ("aac", low_br)
|
||||||
|
|
||||||
# Normalize to 2ch or 6ch output
|
# Normalize to 2ch or 6ch output
|
||||||
output_channels = 6 if channels >= 6 else 2
|
output_channels = 6 if channels >= 6 else 2
|
||||||
|
|
||||||
if output_channels == 2:
|
if output_channels == 2:
|
||||||
# Stereo logic - use AAC
|
# Stereo logic - use AAC
|
||||||
|
stereo_bitrates = [
|
||||||
|
audio_config["stereo"]["low"],
|
||||||
|
audio_config["stereo"]["medium"],
|
||||||
|
audio_config["stereo"]["high"]
|
||||||
|
]
|
||||||
|
|
||||||
if is_1080_class:
|
if is_1080_class:
|
||||||
# 1080p+ stereo
|
# 1080p+ stereo
|
||||||
high_br = audio_config["stereo"]["high"]
|
high_br = audio_config["stereo"]["high"]
|
||||||
if bitrate_kbps > (high_br / 1000): # Above 192k
|
if bitrate_kbps > (high_br / 1000): # Above 192k
|
||||||
return ("aac", high_br)
|
return ("aac", high_br)
|
||||||
else:
|
else:
|
||||||
# Preserve original
|
# Check if within -10kbps of a standard bitrate
|
||||||
return ("copy", 0)
|
matched_br = find_nearest_bitrate(bitrate_kbps, stereo_bitrates)
|
||||||
|
if matched_br > 0:
|
||||||
|
return ("aac", matched_br)
|
||||||
|
else:
|
||||||
|
# Preserve original
|
||||||
|
return ("copy", 0)
|
||||||
else:
|
else:
|
||||||
# 720p stereo
|
# 720p stereo
|
||||||
medium_br = audio_config["stereo"]["medium"]
|
medium_br = audio_config["stereo"]["medium"]
|
||||||
if bitrate_kbps > (medium_br / 1000): # Above 160k
|
if bitrate_kbps > (medium_br / 1000): # Above 160k
|
||||||
return ("aac", medium_br)
|
return ("aac", medium_br)
|
||||||
else:
|
else:
|
||||||
# Preserve original
|
# Check if within -10kbps of a standard bitrate
|
||||||
return ("copy", 0)
|
matched_br = find_nearest_bitrate(bitrate_kbps, stereo_bitrates)
|
||||||
|
if matched_br > 0:
|
||||||
|
return ("aac", matched_br)
|
||||||
|
else:
|
||||||
|
# Preserve original
|
||||||
|
return ("copy", 0)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Multi-channel (6ch+) logic - use EAC3
|
# Multi-channel (6ch+) logic - use EAC3
|
||||||
|
multi_bitrates = [
|
||||||
|
audio_config["multi_channel"]["low"],
|
||||||
|
audio_config["multi_channel"]["medium"]
|
||||||
|
]
|
||||||
low_br = audio_config["multi_channel"]["low"]
|
low_br = audio_config["multi_channel"]["low"]
|
||||||
medium_br = audio_config["multi_channel"]["medium"]
|
medium_br = audio_config["multi_channel"]["medium"]
|
||||||
|
|
||||||
# If below the lowest threshold, copy the original audio instead of re-encoding
|
# Check if source is within -10kbps of a standard bitrate
|
||||||
|
matched_br = find_nearest_bitrate(bitrate_kbps, multi_bitrates)
|
||||||
|
if matched_br > 0:
|
||||||
|
# Within threshold of a standard bitrate, use that one with EAC3
|
||||||
|
return ("eac3", matched_br)
|
||||||
|
|
||||||
|
# Not within threshold, apply normal logic
|
||||||
if bitrate_kbps < (low_br / 1000):
|
if bitrate_kbps < (low_br / 1000):
|
||||||
logger.info(f"Multi-channel audio {bitrate_kbps}kbps < {low_br/1000:.0f}k minimum - copying original to avoid artifical inflation")
|
logger.info(f"Multi-channel audio {bitrate_kbps}kbps < {low_br/1000:.0f}k minimum - copying original to avoid artifical inflation")
|
||||||
return ("copy", 0)
|
return ("copy", 0)
|
||||||
@ -287,13 +347,14 @@ def filter_audio_streams(input_file: Path, streams: list) -> list:
|
|||||||
for stream_info in streams:
|
for stream_info in streams:
|
||||||
index, channels, bitrate, language, metadata, title = stream_info
|
index, channels, bitrate, language, metadata, title = stream_info
|
||||||
|
|
||||||
# Check if commentary (in title or metadata)
|
# Check if special audio (commentary or descriptive) in title or metadata
|
||||||
is_commentary = "comment" in str(title).lower() or "comment" in str(metadata).lower()
|
is_special_audio = ("comment" in str(title).lower() or "comment" in str(metadata).lower() or
|
||||||
|
"descriptive" in str(title).lower() or "descriptive" in str(metadata).lower())
|
||||||
|
|
||||||
# Determine if English (check language field or assume first is English if no language set)
|
# Determine if English (check language field or assume first is English if no language set)
|
||||||
is_english = (language and "eng" in language.lower()) or (not language)
|
is_english = (language and "eng" in language.lower()) or (not language)
|
||||||
|
|
||||||
if is_commentary:
|
if is_special_audio:
|
||||||
commentary_tracks.append((index, channels, bitrate, stream_info))
|
commentary_tracks.append((index, channels, bitrate, stream_info))
|
||||||
elif is_english:
|
elif is_english:
|
||||||
english_tracks.append((index, channels, bitrate, stream_info))
|
english_tracks.append((index, channels, bitrate, stream_info))
|
||||||
|
|||||||
@ -75,6 +75,30 @@ def load_config_xml(path: Path) -> dict:
|
|||||||
reduction_ratio_elem = general.find("reduction_ratio_threshold") if general is not None else None
|
reduction_ratio_elem = general.find("reduction_ratio_threshold") if general is not None else None
|
||||||
reduction_ratio_threshold = float(reduction_ratio_elem.text) if reduction_ratio_elem is not None else 0.5
|
reduction_ratio_threshold = float(reduction_ratio_elem.text) if reduction_ratio_elem is not None else 0.5
|
||||||
|
|
||||||
|
# Extract general section as nested dict for other settings
|
||||||
|
general_dict = {}
|
||||||
|
if general is not None:
|
||||||
|
# Subtitles
|
||||||
|
subtitles_elem = general.find("subtitles")
|
||||||
|
if subtitles_elem is not None:
|
||||||
|
general_dict["subtitles"] = {
|
||||||
|
"enabled": subtitles_elem.find("enabled").text.lower() == "true" if subtitles_elem.find("enabled") is not None else True,
|
||||||
|
"extensions": subtitles_elem.find("extensions").text if subtitles_elem.find("extensions") is not None else ".vtt,.srt,.ass,.ssa,.sub",
|
||||||
|
"codec": subtitles_elem.find("codec").text if subtitles_elem.find("codec") is not None else "srt"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Audio filter
|
||||||
|
audio_filter_elem = general.find("audio_filter")
|
||||||
|
if audio_filter_elem is not None:
|
||||||
|
general_dict["audio_filter"] = {
|
||||||
|
"enabled": audio_filter_elem.find("enabled").text.lower() == "true" if audio_filter_elem.find("enabled") is not None else False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default language for undefined audio tracks
|
||||||
|
default_language_elem = general.find("default_language")
|
||||||
|
if default_language_elem is not None:
|
||||||
|
general_dict["default_language"] = default_language_elem.text if default_language_elem.text else "eng"
|
||||||
|
|
||||||
# --- Path Mappings ---
|
# --- Path Mappings ---
|
||||||
path_mappings = []
|
path_mappings = []
|
||||||
for m in root.findall("path_mappings/map"):
|
for m in root.findall("path_mappings/map"):
|
||||||
@ -164,6 +188,7 @@ def load_config_xml(path: Path) -> dict:
|
|||||||
"ignore_tags": [tag.strip() for tag in ignore_tags],
|
"ignore_tags": [tag.strip() for tag in ignore_tags],
|
||||||
"reduction_ratio_threshold": reduction_ratio_threshold,
|
"reduction_ratio_threshold": reduction_ratio_threshold,
|
||||||
"path_mappings": path_mappings,
|
"path_mappings": path_mappings,
|
||||||
|
"general": general_dict,
|
||||||
"encode": {"cq": cq, "fallback": fallback, "filters": filters},
|
"encode": {"cq": cq, "fallback": fallback, "filters": filters},
|
||||||
"audio": audio,
|
"audio": audio,
|
||||||
"services": services
|
"services": services
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import subprocess
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from core.audio_handler import get_audio_streams, choose_audio_bitrate, filter_audio_streams, prompt_user_audio_selection, prompt_for_title_stripping
|
from core.audio_handler import get_audio_streams, choose_audio_bitrate, filter_audio_streams, prompt_user_audio_selection, prompt_for_title_stripping
|
||||||
|
from core.video_handler import calculate_crop_dimensions
|
||||||
from core.logger_helper import setup_logger
|
from core.logger_helper import setup_logger
|
||||||
|
|
||||||
logger = setup_logger(Path(__file__).parent.parent / "logs")
|
logger = setup_logger(Path(__file__).parent.parent / "logs")
|
||||||
@ -13,7 +14,7 @@ logger = setup_logger(Path(__file__).parent.parent / "logs")
|
|||||||
def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, scale_height: int,
|
def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, scale_height: int,
|
||||||
src_width: int, src_height: int, filter_flags: str, audio_config: dict,
|
src_width: int, src_height: int, filter_flags: str, audio_config: dict,
|
||||||
method: str, bitrate_config: dict, encoder: str = "nvenc", subtitle_files: list = None, audio_language: str = None,
|
method: str, bitrate_config: dict, encoder: str = "nvenc", subtitle_files: list = None, audio_language: str = None,
|
||||||
audio_filter_config: dict = None, test_mode: bool = False, strip_all_titles: bool = False, src_bit_depth: int = None, unforce_subs: bool = False, no_encode: bool = False, start_time: str = None, end_time: str = None):
|
audio_filter_config: dict = None, test_mode: bool = False, strip_all_titles: bool = False, src_bit_depth: int = None, unforce_subs: bool = False, no_encode: bool = False, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None):
|
||||||
"""
|
"""
|
||||||
Execute FFmpeg encoding/re-muxing with structured console output.
|
Execute FFmpeg encoding/re-muxing with structured console output.
|
||||||
|
|
||||||
@ -23,21 +24,6 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
cq: Quality value (0-63, lower=better) for CQ mode
|
cq: Quality value (0-63, lower=better) for CQ mode
|
||||||
scale_width/height: Target resolution dimensions
|
scale_width/height: Target resolution dimensions
|
||||||
src_width/height: Source resolution dimensions
|
src_width/height: Source resolution dimensions
|
||||||
filter_flags: Scaling filter algorithm
|
|
||||||
audio_config: Audio configuration dict
|
|
||||||
method: Encoding method ("CQ" or "Bitrate")
|
|
||||||
bitrate_config: Bitrate configuration
|
|
||||||
encoder: Video codec ("hevc", "av1", or "nvenc")
|
|
||||||
subtitle_files: List of external subtitle file paths
|
|
||||||
audio_language: Language code to tag audio streams
|
|
||||||
audio_filter_config: Audio filtering configuration
|
|
||||||
test_mode: If True, only encode first 15 minutes
|
|
||||||
strip_all_titles: If True, strip title metadata from audio
|
|
||||||
src_bit_depth: Source bit depth (8/10/12)
|
|
||||||
unforce_subs: If True, remove forced flag from subtitles
|
|
||||||
no_encode: If True, copy streams instead of encoding
|
|
||||||
start_time: Start time for trimming (e.g., "00:58:15.250")
|
|
||||||
end_time: End time for trimming (duration from start, e.g., "00:30:00")
|
|
||||||
filter_flags: Scaling filter algorithm (lanczos, bicubic, etc)
|
filter_flags: Scaling filter algorithm (lanczos, bicubic, etc)
|
||||||
audio_config: Audio bitrate configuration dict
|
audio_config: Audio bitrate configuration dict
|
||||||
method: Encoding method - "CQ" or "Bitrate"
|
method: Encoding method - "CQ" or "Bitrate"
|
||||||
@ -51,6 +37,10 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
src_bit_depth: Source bit depth (8/10/12) for encoder auto-selection
|
src_bit_depth: Source bit depth (8/10/12) for encoder auto-selection
|
||||||
unforce_subs: If True, remove forced flag from subtitle tracks
|
unforce_subs: If True, remove forced flag from subtitle tracks
|
||||||
no_encode: If True, copy video/audio (re-mux only, skip encoding)
|
no_encode: If True, copy video/audio (re-mux only, skip encoding)
|
||||||
|
color_bit: If specified (8 or 10), forces HEVC color bit depth. 8-bit uses yuv420p, 10-bit uses p010le.
|
||||||
|
crop_height: If specified, crop video to this height (centered). E.g., 816 for 1920x816 from 1920x1080 source.
|
||||||
|
audio_titles: Dict mapping stream index to custom title. E.g., {1: "Commentary"} sets stream 1 title to "Commentary".
|
||||||
|
audio_channels: Dict mapping stream index to channel count. E.g., {0: 2, 1: 6} forces track 0 to stereo, track 1 to 5.1. Only 2 or 6 allowed.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (orig_size_bytes, output_size_bytes, reduction_ratio)
|
tuple: (orig_size_bytes, output_size_bytes, reduction_ratio)
|
||||||
@ -99,8 +89,18 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
encoder_pix_fmt = "p010le"
|
encoder_pix_fmt = "p010le"
|
||||||
encoder_bit_depth = "10-bit"
|
encoder_bit_depth = "10-bit"
|
||||||
|
|
||||||
# Auto-select encoder based on detected source bit depth if provided
|
# Handle --color-bit override if specified (only for HEVC)
|
||||||
if src_bit_depth is not None:
|
if color_bit is not None and encoder == "hevc":
|
||||||
|
if color_bit == 8:
|
||||||
|
encoder_pix_fmt = "yuv420p"
|
||||||
|
encoder_bit_depth = "8-bit"
|
||||||
|
logger.info(f"Using --color-bit {color_bit}: HEVC NVENC 8-bit (yuv420p)")
|
||||||
|
elif color_bit == 10:
|
||||||
|
encoder_pix_fmt = "p010le"
|
||||||
|
encoder_bit_depth = "10-bit"
|
||||||
|
logger.info(f"Using --color-bit {color_bit}: HEVC NVENC 10-bit (p010le)")
|
||||||
|
# Auto-select encoder based on detected source bit depth if provided (only if --color-bit not specified)
|
||||||
|
elif src_bit_depth is not None and color_bit is None:
|
||||||
if src_bit_depth >= 10:
|
if src_bit_depth >= 10:
|
||||||
# Source is 10-bit or higher - use HEVC NVENC
|
# Source is 10-bit or higher - use HEVC NVENC
|
||||||
encoder_name = "HEVC NVENC"
|
encoder_name = "HEVC NVENC"
|
||||||
@ -124,10 +124,26 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
# Build simple console summary
|
# Build simple console summary
|
||||||
audio_summary_lines = []
|
audio_summary_lines = []
|
||||||
for (index, channels, avg_bitrate, src_lang, meta_bitrate, title, codec_name) in streams:
|
for (index, channels, avg_bitrate, src_lang, meta_bitrate, title, codec_name) in streams:
|
||||||
# Normalize to 2ch or 6ch output
|
# Determine final title (considering custom titles override)
|
||||||
|
final_title = audio_titles.get(index, title) if audio_titles else title
|
||||||
|
|
||||||
|
# Check if this is a commentary track (original or custom title)
|
||||||
|
is_commentary = final_title and "commentary" in final_title.lower()
|
||||||
|
|
||||||
|
# Determine output channels: audio_channels override takes precedence
|
||||||
is_1080_class = scale_height >= 1080 or scale_width >= 1920
|
is_1080_class = scale_height >= 1080 or scale_width >= 1920
|
||||||
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
if audio_channels and index in audio_channels:
|
||||||
codec, br = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class)
|
# User explicitly specified channel count for this stream
|
||||||
|
output_channels = audio_channels[index]
|
||||||
|
channels_override = True
|
||||||
|
elif is_commentary:
|
||||||
|
output_channels = 2 # Commentary always stereo
|
||||||
|
channels_override = False
|
||||||
|
else:
|
||||||
|
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
||||||
|
channels_override = False
|
||||||
|
|
||||||
|
codec, br = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary)
|
||||||
|
|
||||||
if codec == "copy":
|
if codec == "copy":
|
||||||
action = "COPY"
|
action = "COPY"
|
||||||
@ -143,34 +159,41 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
lang_info = f"{src_lang} → {audio_language}" if audio_language else src_lang
|
lang_info = f"{src_lang} → {audio_language}" if audio_language else src_lang
|
||||||
|
|
||||||
# Include title in display if present
|
# Include title in display if present
|
||||||
title_info = f" [{title}]" if title else ""
|
title_info = f" [{final_title}]" if final_title else ""
|
||||||
line = f" - Stream #{index}: {channels}ch→{output_channels}ch | {lang_info} | Detected: {codec_name} {avg_bitrate}kbps | Output: {output_codec} {output_bitrate} ({action}){title_info}"
|
# Add override note if channels were forced
|
||||||
|
override_note = " [FORCED]" if channels_override else ""
|
||||||
|
line = f" - Stream #{index}: {channels}ch→{output_channels}ch | {lang_info} | Detected: {codec_name} {avg_bitrate}kbps | Output: {output_codec} {output_bitrate} ({action}){title_info}{override_note}"
|
||||||
audio_summary_lines.append(line)
|
audio_summary_lines.append(line)
|
||||||
|
|
||||||
cmd = ["ffmpeg","-y"]
|
cmd = ["ffmpeg","-y","-i",str(input_file)]
|
||||||
|
|
||||||
# Add trim parameters if splitting
|
|
||||||
if start_time:
|
|
||||||
cmd.extend(["-ss", start_time])
|
|
||||||
|
|
||||||
cmd.extend(["-i", str(input_file)])
|
|
||||||
|
|
||||||
# Add subtitle inputs if present
|
# Add subtitle inputs if present
|
||||||
if subtitle_files:
|
if subtitle_files:
|
||||||
for sub_file in subtitle_files:
|
for sub_file in subtitle_files:
|
||||||
cmd.extend(["-i", str(sub_file)])
|
cmd.extend(["-i", str(sub_file)])
|
||||||
|
|
||||||
# Add trim duration if needed (for split end_time)
|
# In test mode, only encode first 15 minutes
|
||||||
if end_time:
|
if test_mode:
|
||||||
cmd.extend(["-t", end_time])
|
|
||||||
elif test_mode:
|
|
||||||
# In test mode, only encode first 15 minutes
|
|
||||||
cmd.extend(["-t", "900"]) # 900 seconds = 15 minutes
|
cmd.extend(["-t", "900"]) # 900 seconds = 15 minutes
|
||||||
|
|
||||||
# Only add scale filter if encoding (not copying)
|
# Build video filters (crop and/or scale)
|
||||||
|
video_filters = []
|
||||||
|
|
||||||
|
# Add crop filter first (if specified)
|
||||||
|
if crop_height and not no_encode:
|
||||||
|
crop_dims = calculate_crop_dimensions(src_height, crop_height)
|
||||||
|
if crop_dims["ffmpeg_filter"]:
|
||||||
|
video_filters.append(crop_dims["ffmpeg_filter"])
|
||||||
|
print(f"ℹ️ Applying crop: {crop_dims['ffmpeg_filter']} ({src_height}p → {crop_height}p)")
|
||||||
|
|
||||||
|
# Add scale filter (if encoding, not copying)
|
||||||
if not no_encode:
|
if not no_encode:
|
||||||
cmd.extend([
|
video_filters.append(f"scale={scale_width}:{scale_height}:flags={filter_flags}:force_original_aspect_ratio=decrease")
|
||||||
"-vf",f"scale={scale_width}:{scale_height}:flags={filter_flags}:force_original_aspect_ratio=decrease"])
|
|
||||||
|
# Combine all filters with commas (ffmpeg filter chain syntax)
|
||||||
|
if video_filters:
|
||||||
|
filter_chain = ",".join(video_filters)
|
||||||
|
cmd.extend(["-vf", filter_chain])
|
||||||
|
|
||||||
cmd.extend(["-map","0:v:0"]) # Map only first actual video stream (skips attached pictures)
|
cmd.extend(["-map","0:v:0"]) # Map only first actual video stream (skips attached pictures)
|
||||||
|
|
||||||
@ -203,26 +226,48 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
cmd += ["-b:v", vb, "-maxrate", maxrate, "-bufsize", bufsize]
|
cmd += ["-b:v", vb, "-maxrate", maxrate, "-bufsize", bufsize]
|
||||||
|
|
||||||
for i, (index, channels, avg_bitrate, src_lang, meta_bitrate, title, codec_name) in enumerate(streams):
|
for i, (index, channels, avg_bitrate, src_lang, meta_bitrate, title, codec_name) in enumerate(streams):
|
||||||
# Normalize to 2ch or 6ch output
|
# Determine final title (considering custom titles override)
|
||||||
|
final_title = audio_titles.get(index, title) if audio_titles else title
|
||||||
|
|
||||||
|
# Debug: Log what we're working with
|
||||||
|
if i == 0: # Only log once per file
|
||||||
|
logger.debug(f"audio_titles dict received: {audio_titles}")
|
||||||
|
logger.debug(f"Stream {index}: original_title='{title}', final_title='{final_title}', audio_titles_present={audio_titles is not None}")
|
||||||
|
|
||||||
|
# Check if this is a commentary track (original or custom title)
|
||||||
|
is_commentary = final_title and "commentary" in final_title.lower()
|
||||||
|
|
||||||
|
# Determine output channels: audio_channels override takes precedence
|
||||||
|
# BUT: Commentary tracks ALWAYS max out at 2ch (stereo) unless explicitly overridden
|
||||||
is_1080_class = scale_height >= 1080 or scale_width >= 1920
|
is_1080_class = scale_height >= 1080 or scale_width >= 1920
|
||||||
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
if audio_channels and index in audio_channels:
|
||||||
|
# User explicitly specified channel count for this stream
|
||||||
|
output_channels = audio_channels[index]
|
||||||
|
logger.info(f"Stream #{index}: Audio channels override applied: {channels}ch → {output_channels}ch")
|
||||||
|
elif is_commentary:
|
||||||
|
output_channels = 2 # Commentary always stereo
|
||||||
|
else:
|
||||||
|
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
||||||
|
|
||||||
# If no_encode is True, always copy audio
|
# If no_encode is True, always copy audio
|
||||||
if no_encode:
|
if no_encode:
|
||||||
codec, br = "copy", avg_bitrate
|
codec, br = "copy", avg_bitrate
|
||||||
else:
|
else:
|
||||||
codec, br = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class)
|
codec, br = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary)
|
||||||
|
|
||||||
# Check if title should be stripped (for this stream or globally)
|
# Check if title should be stripped (for this stream or globally)
|
||||||
# Preserve any stream with "commentary" in the title, regardless of strip_all_titles
|
# Preserve any stream with "commentary" or "descriptive" in the title, regardless of strip_all_titles
|
||||||
is_commentary = title and "commentary" in title.lower()
|
is_special_audio = title and ("commentary" in title.lower() or "descriptive" in title.lower())
|
||||||
should_strip = strip_all_titles and not is_commentary
|
should_strip = strip_all_titles and not is_special_audio
|
||||||
|
|
||||||
# Log title stripping decisions for debugging (debug level, not info)
|
# Log title stripping decisions for debugging (debug level, not info)
|
||||||
logger.debug(f"Stream {index}: title='{title}', is_commentary={is_commentary}, strip_all_titles={strip_all_titles}, should_strip={should_strip}")
|
logger.debug(f"Stream {index}: title='{final_title}', is_commentary={is_commentary}, is_special_audio={is_special_audio}, strip_all_titles={strip_all_titles}, should_strip={should_strip}")
|
||||||
|
|
||||||
if strip_all_titles and is_commentary:
|
if is_commentary:
|
||||||
logger.debug(f"Stream {index}: ✓ Preserving title '{title}' (contains 'commentary')")
|
logger.info(f"Stream #{index}: Commentary track detected (forcing 2ch stereo)")
|
||||||
|
|
||||||
|
if strip_all_titles and is_special_audio:
|
||||||
|
logger.debug(f"Stream {index}: ✓ Preserving title '{title}' (special audio track)")
|
||||||
|
|
||||||
if codec == "copy":
|
if codec == "copy":
|
||||||
# Preserve original audio
|
# Preserve original audio
|
||||||
@ -230,8 +275,11 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
# Only add language metadata if explicitly provided
|
# Only add language metadata if explicitly provided
|
||||||
if audio_language:
|
if audio_language:
|
||||||
cmd += [f"-metadata:s:a:{i}", f"language={audio_language}"]
|
cmd += [f"-metadata:s:a:{i}", f"language={audio_language}"]
|
||||||
# Strip title metadata if requested (but preserve commentary tracks)
|
# Apply custom title if provided for this stream (takes precedence)
|
||||||
if should_strip:
|
if audio_titles and index in audio_titles:
|
||||||
|
cmd += [f"-metadata:s:a:{i}", f"title={audio_titles[index]}"]
|
||||||
|
# Strip title metadata if requested (but preserve commentary tracks and custom titles)
|
||||||
|
elif should_strip:
|
||||||
cmd += [f"-metadata:s:a:{i}", "title="]
|
cmd += [f"-metadata:s:a:{i}", "title="]
|
||||||
else:
|
else:
|
||||||
# Re-encode with target bitrate
|
# Re-encode with target bitrate
|
||||||
@ -255,8 +303,11 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
# Only add language metadata if explicitly provided
|
# Only add language metadata if explicitly provided
|
||||||
if audio_language:
|
if audio_language:
|
||||||
cmd += [f"-metadata:s:a:{i}", f"language={audio_language}"]
|
cmd += [f"-metadata:s:a:{i}", f"language={audio_language}"]
|
||||||
# Strip title metadata if requested (but preserve commentary tracks)
|
# Apply custom title if provided for this stream (takes precedence)
|
||||||
if should_strip:
|
if audio_titles and index in audio_titles:
|
||||||
|
cmd += [f"-metadata:s:a:{i}", f"title={audio_titles[index]}"]
|
||||||
|
# Strip title metadata if requested (but preserve commentary tracks and custom titles)
|
||||||
|
elif should_strip:
|
||||||
cmd += [f"-metadata:s:a:{i}", "title="]
|
cmd += [f"-metadata:s:a:{i}", "title="]
|
||||||
# Add subtitle codec and metadata if subtitles are present
|
# Add subtitle codec and metadata if subtitles are present
|
||||||
if subtitle_files:
|
if subtitle_files:
|
||||||
@ -266,7 +317,9 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
|||||||
if unforce_subs:
|
if unforce_subs:
|
||||||
cmd += ["-disposition:s:" + str(i), "-forced"]
|
cmd += ["-disposition:s:" + str(i), "-forced"]
|
||||||
else:
|
else:
|
||||||
cmd += ["-c:s", "copy"]
|
# Convert mov_text (MP4 subtitles) to subrip (MKV-compatible)
|
||||||
|
# Use "copy" for other formats like subrip, ass, ssa, webvtt that work in MKV
|
||||||
|
cmd += ["-c:s", "subrip"]
|
||||||
# For embedded subtitles, still apply -disposition if unforce_subs is enabled
|
# For embedded subtitles, still apply -disposition if unforce_subs is enabled
|
||||||
if unforce_subs:
|
if unforce_subs:
|
||||||
# Apply to all embedded subtitle streams
|
# Apply to all embedded subtitle streams
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
@ -49,82 +48,6 @@ def get_default_cq(folder: Path, config: dict, resolution: str, encoder: str = "
|
|||||||
return cq_config.get(key, 28) # Default fallback to 28
|
return cq_config.get(key, 28) # Default fallback to 28
|
||||||
|
|
||||||
|
|
||||||
def get_media_context(file: Path, root_folder: Path) -> dict:
|
|
||||||
"""
|
|
||||||
Extract media context from file path for structured logging.
|
|
||||||
|
|
||||||
Parses directory structure to identify show name, media type (TV/Movie),
|
|
||||||
season/episode numbers for grouping logs later.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file: File path to analyze
|
|
||||||
root_folder: Root processing folder to use as reference
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict with keys: media_type, show_name, season (optional), episode (optional), video_filename
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
P:\\tv\\Breaking Bad\\season01\\episode01.mkv
|
|
||||||
→ {"media_type": "tv", "show_name": "Breaking Bad", "season": "01", "episode": "01"}
|
|
||||||
|
|
||||||
P:\\movies\\Inception.mkv
|
|
||||||
→ {"media_type": "movie", "show_name": "Inception"}
|
|
||||||
"""
|
|
||||||
parts = file.parts
|
|
||||||
root_parts = root_folder.parts
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"video_filename": file.name,
|
|
||||||
"media_type": None,
|
|
||||||
"show_name": None,
|
|
||||||
"season": None,
|
|
||||||
"episode": None
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find where media type (tv/movie/anime) appears in path
|
|
||||||
path_lower = str(file).lower()
|
|
||||||
|
|
||||||
if "\\tv\\" in path_lower or "/tv/" in path_lower:
|
|
||||||
context["media_type"] = "tv"
|
|
||||||
elif "\\anime\\" in path_lower or "/anime/" in path_lower:
|
|
||||||
context["media_type"] = "anime"
|
|
||||||
elif "\\movies\\" in path_lower or "/movies/" in path_lower:
|
|
||||||
context["media_type"] = "movie"
|
|
||||||
else:
|
|
||||||
# Default to movie if path structure unclear
|
|
||||||
context["media_type"] = "other"
|
|
||||||
|
|
||||||
# Extract show name (directory immediately after media type)
|
|
||||||
try:
|
|
||||||
for i, part in enumerate(parts):
|
|
||||||
part_lower = part.lower()
|
|
||||||
if part_lower in ("tv", "anime", "movies"):
|
|
||||||
# Next part is show name
|
|
||||||
if i + 1 < len(parts):
|
|
||||||
context["show_name"] = parts[i + 1]
|
|
||||||
|
|
||||||
# For TV/anime, check if there's a season folder
|
|
||||||
if context["media_type"] in ("tv", "anime") and i + 2 < len(parts):
|
|
||||||
season_part = parts[i + 2].lower()
|
|
||||||
# Pattern: "season01", "s01", "season 1", etc.
|
|
||||||
import re
|
|
||||||
season_match = re.search(r's(?:eason)?\s*(\d+)', season_part)
|
|
||||||
if season_match:
|
|
||||||
context["season"] = season_match.group(1).zfill(2)
|
|
||||||
|
|
||||||
# Extract episode from filename
|
|
||||||
# Pattern: "e01", "episode01", "01", etc.
|
|
||||||
filename_lower = file.stem.lower()
|
|
||||||
ep_match = re.search(r'e(?:pisode)?\s*(\d+)', filename_lower)
|
|
||||||
if ep_match:
|
|
||||||
context["episode"] = ep_match.group(1).zfill(2)
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Could not parse media context from {file}: {e}")
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def _cleanup_temp_files(temp_input: Path, temp_output: Path):
|
def _cleanup_temp_files(temp_input: Path, temp_output: Path):
|
||||||
"""Helper function to clean up temporary input and output files."""
|
"""Helper function to clean up temporary input and output files."""
|
||||||
try:
|
try:
|
||||||
@ -142,80 +65,6 @@ def _cleanup_temp_files(temp_input: Path, temp_output: Path):
|
|||||||
logger.warning(f"Could not delete temp output {temp_output.name}: {e}")
|
logger.warning(f"Could not delete temp output {temp_output.name}: {e}")
|
||||||
|
|
||||||
|
|
||||||
def encode_with_split(temp_input: Path, temp_output: Path, cq: int, scale_width: int, scale_height: int,
|
|
||||||
src_width: int, src_height: int, filter_flags: str, audio_config: dict,
|
|
||||||
method: str, bitrate_config: dict, split_time: str, processing_folder: Path,
|
|
||||||
encoder: str = "hevc", src_bit_depth: int = 10, subtitle_files: list = None,
|
|
||||||
audio_language: str = None, audio_filter_config: dict = None,
|
|
||||||
strip_all_titles: bool = False, unforce_subs: bool = False) -> tuple:
|
|
||||||
"""
|
|
||||||
Encode video with split at specified timestamp, creating part1 and part2 files with full encoding.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
temp_input: Source file path
|
|
||||||
temp_output: Base output file path (will create part1 and part2 versions)
|
|
||||||
cq: Quality value for encoding
|
|
||||||
split_time: Timestamp to split at (e.g., "00:58:15.250")
|
|
||||||
processing_folder: Folder where temp files are stored
|
|
||||||
encoder: Video encoder ("hevc" or "av1")
|
|
||||||
src_bit_depth: Source bit depth for encoder selection
|
|
||||||
subtitle_files: List of external subtitle paths
|
|
||||||
audio_language: Language code to tag audio
|
|
||||||
audio_filter_config: Audio filtering configuration
|
|
||||||
strip_all_titles: Strip title metadata from audio
|
|
||||||
unforce_subs: Remove forced subtitle flags
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
tuple: (orig_size, part1_size + part2_size, combined_reduction_ratio, [part1_file, part2_file])
|
|
||||||
"""
|
|
||||||
orig_size = temp_input.stat().st_size
|
|
||||||
|
|
||||||
# Create part1 and part2 output paths
|
|
||||||
part1_output = processing_folder / temp_output.name.replace(".mkv", "_part1.mkv")
|
|
||||||
part2_output = processing_folder / temp_output.name.replace(".mkv", "_part2.mkv")
|
|
||||||
|
|
||||||
print(f"\n🎬 SPLIT MODE: Encoding two parts at {split_time}")
|
|
||||||
logger.info(f"Encoding with split at {split_time}: creating {part1_output.name} and {part2_output.name}")
|
|
||||||
|
|
||||||
# Part 1: from start to split_time
|
|
||||||
print(f"📍 Part 1: 00:00:00 → {split_time}")
|
|
||||||
try:
|
|
||||||
part1_size, _, _ = run_ffmpeg(
|
|
||||||
temp_input, part1_output, cq, scale_width, scale_height, src_width, src_height,
|
|
||||||
filter_flags, audio_config, method, bitrate_config, encoder, subtitle_files,
|
|
||||||
audio_language, audio_filter_config, False, strip_all_titles, src_bit_depth,
|
|
||||||
unforce_subs, False, start_time=None, end_time=split_time
|
|
||||||
)
|
|
||||||
print(f"✓ Part 1 encoded: {part1_output.stat().st_size / 1e6:.2f} MB")
|
|
||||||
logger.info(f"Part 1 complete: {part1_output.stat().st_size / 1e6:.2f} MB")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Part 1 encoding failed: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Part 2: from split_time to end
|
|
||||||
print(f"📍 Part 2: {split_time} → end")
|
|
||||||
try:
|
|
||||||
part2_size, _, _ = run_ffmpeg(
|
|
||||||
temp_input, part2_output, cq, scale_width, scale_height, src_width, src_height,
|
|
||||||
filter_flags, audio_config, method, bitrate_config, encoder, subtitle_files,
|
|
||||||
audio_language, audio_filter_config, False, strip_all_titles, src_bit_depth,
|
|
||||||
unforce_subs, False, start_time=split_time, end_time=None
|
|
||||||
)
|
|
||||||
print(f"✓ Part 2 encoded: {part2_output.stat().st_size / 1e6:.2f} MB")
|
|
||||||
logger.info(f"Part 2 complete: {part2_output.stat().st_size / 1e6:.2f} MB")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Part 2 encoding failed: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Calculate combined size and return
|
|
||||||
combined_size = part1_output.stat().st_size + part2_output.stat().st_size
|
|
||||||
reduction_ratio = combined_size / orig_size
|
|
||||||
|
|
||||||
print(f"\n✅ Split encoding complete: {orig_size / 1e6:.2f} MB → {combined_size / 1e6:.2f} MB ({reduction_ratio:.1%})")
|
|
||||||
|
|
||||||
return orig_size, combined_size, reduction_ratio, [part1_output, part2_output]
|
|
||||||
|
|
||||||
|
|
||||||
def should_skip_file(file: Path, no_encode: bool, unforce_subs: bool, force_process: bool, ignore_tags: list, travel_output_folder: Path) -> tuple:
|
def should_skip_file(file: Path, no_encode: bool, unforce_subs: bool, force_process: bool, ignore_tags: list, travel_output_folder: Path) -> tuple:
|
||||||
"""
|
"""
|
||||||
Determine if a file should be skipped from processing based on multiple criteria.
|
Determine if a file should be skipped from processing based on multiple criteria.
|
||||||
@ -249,9 +98,9 @@ def should_skip_file(file: Path, no_encode: bool, unforce_subs: bool, force_proc
|
|||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str, config: dict, tracker_file: Path, test_mode: bool = False, audio_language: str = None, filter_audio: bool = None, audio_select: str = None, encoder: str = "hevc", strip_all_titles: bool = False, travel_output_folder: Path = None, unforce_subs: bool = False, no_encode: bool = False, force_process: bool = False, replace_file: bool = False, wait_seconds: int = 0, split_time: str = None, target_file: Path = None):
|
def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str, config: dict, tracker_file: Path, test_mode: bool = False, audio_language: str = None, filter_audio: bool = None, audio_select: str = None, encoder: str = "hevc", strip_all_titles: bool = False, travel_output_folder: Path = None, unforce_subs: bool = False, no_encode: bool = False, force_process: bool = False, replace_file: bool = False, wait_seconds: int = 0, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None, title_suffix: str = None, default_language: str = None, no_replace_und: bool = False):
|
||||||
"""
|
"""
|
||||||
Process video files in folder with appropriate encoding settings.
|
Process all video files in folder with appropriate encoding settings.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
folder: Input folder path
|
folder: Input folder path
|
||||||
@ -269,11 +118,14 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
unforce_subs: If True, remove forced flag from all subtitle tracks.
|
unforce_subs: If True, remove forced flag from all subtitle tracks.
|
||||||
no_encode: If True, skip encoding and copy video/audio streams as-is. Useful with --unforce-subs for re-muxing only.
|
no_encode: If True, skip encoding and copy video/audio streams as-is. Useful with --unforce-subs for re-muxing only.
|
||||||
force_process: If True, process files even if they match ignore_tags (e.g., already encoded files).
|
force_process: If True, process files even if they match ignore_tags (e.g., already encoded files).
|
||||||
|
crop_height: Optional crop height in pixels (e.g., 816 for 1920x816 crop from 1920x1080 source). If None, no crop applied.
|
||||||
replace_file: If True, replace original file instead of creating suffix version. Requires no_encode=True.
|
replace_file: If True, replace original file instead of creating suffix version. Requires no_encode=True.
|
||||||
wait_seconds: Seconds to wait after each successful file (for Plex detection). 0 = no wait.
|
wait_seconds: Seconds to wait after each successful file (for Plex detection). 0 = no wait.
|
||||||
travel_output_folder: If provided, move encoded files to this folder instead of original location.
|
travel_output_folder: If provided, move encoded files to this folder instead of original location.
|
||||||
split_time: If provided, split video at this timestamp (e.g., "00:58:15.250"). Creates part1 and part2 files.
|
color_bit: If specified (8 or 10), forces HEVC color bit depth. 8-bit uses yuv420p, 10-bit uses p010le. Only valid with hevc encoder.
|
||||||
target_file: If provided, only process this specific file (instead of all files in folder).
|
title_suffix: Optional text to insert before main suffix (e.g., "1080p" or "v2"). If None, uses config file setting.
|
||||||
|
default_language: Default language code for undefined (und) audio tracks (e.g., 'eng', 'spa'). If None, uses config default.
|
||||||
|
no_replace_und: If True, disable replacement of undefined language tags with default language.
|
||||||
"""
|
"""
|
||||||
if not folder.exists():
|
if not folder.exists():
|
||||||
print(f"❌ Folder not found: {folder}")
|
print(f"❌ Folder not found: {folder}")
|
||||||
@ -284,6 +136,11 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
bitrate_config = config["encode"]["fallback"]
|
bitrate_config = config["encode"]["fallback"]
|
||||||
filters_config = config["encode"]["filters"]
|
filters_config = config["encode"]["filters"]
|
||||||
suffix = config["suffix"]
|
suffix = config["suffix"]
|
||||||
|
# Use provided title_suffix, or get from config, or use empty string
|
||||||
|
if title_suffix is None:
|
||||||
|
title_suffix = config.get("title_suffix", "")
|
||||||
|
# Create combined suffix (title_suffix appears before main suffix)
|
||||||
|
combined_suffix = title_suffix + suffix if title_suffix else suffix
|
||||||
extensions = config["extensions"]
|
extensions = config["extensions"]
|
||||||
ignore_tags = config["ignore_tags"]
|
ignore_tags = config["ignore_tags"]
|
||||||
reduction_ratio_threshold = config["reduction_ratio_threshold"]
|
reduction_ratio_threshold = config["reduction_ratio_threshold"]
|
||||||
@ -303,7 +160,35 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
processing_folder = Path(config["processing_folder"])
|
processing_folder = Path(config["processing_folder"])
|
||||||
processing_folder.mkdir(parents=True, exist_ok=True)
|
processing_folder.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# ===== Handle default language for undefined (und) audio tracks =====
|
||||||
|
# Determine effective default language
|
||||||
|
effective_default_lang = None
|
||||||
|
if not no_replace_und: # Only if replacement is enabled
|
||||||
|
# Priority: CLI arg > config setting > 'und' (disabled)
|
||||||
|
if default_language:
|
||||||
|
effective_default_lang = default_language
|
||||||
|
print(f"✅ Using CLI default language: {effective_default_lang}")
|
||||||
|
logger.info(f"Default language from CLI: {effective_default_lang}")
|
||||||
|
else:
|
||||||
|
# Get from config
|
||||||
|
config_default_lang = config.get("general", {}).get("default_language", "eng")
|
||||||
|
if config_default_lang and config_default_lang != "und":
|
||||||
|
effective_default_lang = config_default_lang
|
||||||
|
print(f"✅ Using config default language: {effective_default_lang}")
|
||||||
|
logger.info(f"Default language from config: {effective_default_lang}")
|
||||||
|
|
||||||
|
if no_replace_und:
|
||||||
|
print(f"⏸️ Undefined (und) language tag replacement is DISABLED (--no-replace-und)")
|
||||||
|
logger.info("und→default language replacement is disabled")
|
||||||
|
elif effective_default_lang:
|
||||||
|
print(f"ℹ️ Will replace 'und' audio language with: {effective_default_lang}")
|
||||||
|
logger.info(f"und→default language enabled: und → {effective_default_lang}")
|
||||||
|
else:
|
||||||
|
print(f"ℹ️ und audio language replacement is disabled or configured as 'und'")
|
||||||
|
logger.info("und→default language disabled (configured as 'und')")
|
||||||
|
|
||||||
# Determine if we're in smart mode (no explicit mode specified)
|
# Determine if we're in smart mode (no explicit mode specified)
|
||||||
|
|
||||||
is_smart_mode = transcode_mode not in ["cq", "bitrate"] # Default/smart mode
|
is_smart_mode = transcode_mode not in ["cq", "bitrate"] # Default/smart mode
|
||||||
is_forced_cq = transcode_mode == "cq"
|
is_forced_cq = transcode_mode == "cq"
|
||||||
is_forced_bitrate = transcode_mode == "bitrate"
|
is_forced_bitrate = transcode_mode == "bitrate"
|
||||||
@ -324,18 +209,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
print(f"{'='*60}\n")
|
print(f"{'='*60}\n")
|
||||||
|
|
||||||
skipped_count = 0
|
skipped_count = 0
|
||||||
# If target_file is specified, only process that file; otherwise process all files in folder
|
for file in folder.rglob("*"):
|
||||||
if target_file:
|
|
||||||
files_to_process = [target_file]
|
|
||||||
print(f"📄 Processing single file: {target_file.name}\n")
|
|
||||||
else:
|
|
||||||
files_to_process = folder.rglob("*")
|
|
||||||
|
|
||||||
for file in files_to_process:
|
|
||||||
# Skip hidden files/directories (starting with . or ._)
|
|
||||||
if file.name.startswith('.') or file.name.startswith('._'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if file.suffix.lower() not in extensions:
|
if file.suffix.lower() not in extensions:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -352,11 +226,8 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
logger.info(f"Skipped {skipped_count} file(s)")
|
logger.info(f"Skipped {skipped_count} file(s)")
|
||||||
skipped_count = 0
|
skipped_count = 0
|
||||||
|
|
||||||
# Extract media context for structured logging
|
|
||||||
media_context = get_media_context(file, folder)
|
|
||||||
|
|
||||||
print("="*60)
|
print("="*60)
|
||||||
logger.info(f"Processing: {file.name}", extra=media_context)
|
logger.info(f"Processing: {file.name}")
|
||||||
print(f"📁 Processing: {file.name}")
|
print(f"📁 Processing: {file.name}")
|
||||||
|
|
||||||
temp_input = (processing_folder / file.name).resolve()
|
temp_input = (processing_folder / file.name).resolve()
|
||||||
@ -459,8 +330,9 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
content_cq = encoder_cq_config.get(cq_key, 32)
|
content_cq = encoder_cq_config.get(cq_key, 32)
|
||||||
file_cq = cq if cq is not None else content_cq
|
file_cq = cq if cq is not None else content_cq
|
||||||
|
|
||||||
# Output file with suffix in processing folder (always .mkv container)
|
# Output file with title_suffix (if any) and main suffix in processing folder (always .mkv container)
|
||||||
temp_output = (processing_folder / f"{file.stem}{suffix}.mkv").resolve()
|
combined_suffix = title_suffix + suffix if title_suffix else suffix
|
||||||
|
temp_output = (processing_folder / f"{file.stem}{combined_suffix}.mkv").resolve()
|
||||||
|
|
||||||
# Determine which method to try first
|
# Determine which method to try first
|
||||||
if is_forced_bitrate:
|
if is_forced_bitrate:
|
||||||
@ -486,46 +358,26 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
# Use config file setting (if present)
|
# Use config file setting (if present)
|
||||||
audio_filter_config = config.get("general", {}).get("audio_filter", {})
|
audio_filter_config = config.get("general", {}).get("audio_filter", {})
|
||||||
|
|
||||||
# Handle split encoding if split_time is provided
|
# ===== Determine effective audio language to apply =====
|
||||||
if split_time:
|
# Priority: CLI --language > (detected und + default_language) > detected language
|
||||||
orig_size, out_size, reduction_ratio, split_output_files = encode_with_split(
|
effective_audio_language = audio_language
|
||||||
temp_input, temp_output, file_cq, res_width, res_height, src_width, src_height,
|
|
||||||
filter_flags, audio_config, method, bitrate_config, split_time, processing_folder,
|
|
||||||
actual_encoder, src_bit_depth, [subtitle_file] if subtitle_file else None,
|
|
||||||
audio_language, audio_filter_config, strip_all_titles, unforce_subs
|
|
||||||
)
|
|
||||||
# For split mode, we need to process both files separately in the save logic
|
|
||||||
# For now, save both files and mark them as processed
|
|
||||||
print(f"📦 Processing split files: {[f.name for f in split_output_files]}")
|
|
||||||
consecutive_failures = 0
|
|
||||||
|
|
||||||
# Save both parts
|
# If no explicit CLI language, check if we should replace 'und' with default
|
||||||
for part_num, part_file in enumerate(split_output_files, 1):
|
if not audio_language and effective_default_lang:
|
||||||
part_media_context = {**media_context, "split_part": part_num, "split_time": split_time}
|
# Get audio streams to check their languages
|
||||||
dest_file = file.parent / part_file.name
|
streams = get_audio_streams(temp_input)
|
||||||
shutil.move(part_file, dest_file)
|
if streams:
|
||||||
print(f"✅ Part {part_num} saved: {dest_file.name}")
|
# Check if the first (or any primary) audio stream is 'und'
|
||||||
logger.info(f"Part {part_num} saved: {dest_file.name}", extra=part_media_context)
|
first_stream_lang = streams[0][3] # 4th element is language
|
||||||
|
if first_stream_lang == "und":
|
||||||
# Track in CSV
|
effective_audio_language = effective_default_lang
|
||||||
with open(tracker_file, "a", newline="", encoding="utf-8") as f:
|
logger.info(f"First audio stream is 'und', replacing with default language: {effective_audio_language}")
|
||||||
writer = csv.writer(f)
|
print(f"🔄 Audio stream detected as 'und', will tag as: {effective_audio_language}")
|
||||||
f_type = "tv" if is_tv else ("anime" if is_anime else "movie")
|
|
||||||
show = file.parent.name
|
|
||||||
for part_num in [1, 2]:
|
|
||||||
writer.writerow([
|
|
||||||
f"{f_type}_split", show, f"{file.stem}_part{part_num}.mkv",
|
|
||||||
orig_size / 1e6, (out_size / 2) / 1e6, reduction_ratio * 100,
|
|
||||||
f"{src_width}x{src_height}", f"{res_width}x{res_height}", 0,
|
|
||||||
file_cq, "Split"
|
|
||||||
])
|
|
||||||
|
|
||||||
continue # Move to next file
|
|
||||||
|
|
||||||
orig_size, out_size, reduction_ratio = run_ffmpeg(
|
orig_size, out_size, reduction_ratio = run_ffmpeg(
|
||||||
temp_input, temp_output, file_cq, res_width, res_height, src_width, src_height,
|
temp_input, temp_output, file_cq, res_width, res_height, src_width, src_height,
|
||||||
filter_flags, audio_config, method, bitrate_config, actual_encoder, [subtitle_file] if subtitle_file else None, audio_language,
|
filter_flags, audio_config, method, bitrate_config, actual_encoder, [subtitle_file] if subtitle_file else None, effective_audio_language,
|
||||||
audio_filter_config, test_mode, strip_all_titles, src_bit_depth, unforce_subs, no_encode
|
audio_filter_config, test_mode, strip_all_titles, src_bit_depth, unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if encode met size target
|
# Check if encode met size target
|
||||||
@ -567,7 +419,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
'subtitle_file': subtitle_file,
|
'subtitle_file': subtitle_file,
|
||||||
'src_bit_depth': src_bit_depth,
|
'src_bit_depth': src_bit_depth,
|
||||||
'encoder': actual_encoder,
|
'encoder': actual_encoder,
|
||||||
'media_context': media_context
|
'effective_audio_language': effective_audio_language
|
||||||
})
|
})
|
||||||
consecutive_failures += 1
|
consecutive_failures += 1
|
||||||
if consecutive_failures >= max_consecutive:
|
if consecutive_failures >= max_consecutive:
|
||||||
@ -619,7 +471,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
'file_cq': file_cq,
|
'file_cq': file_cq,
|
||||||
'is_tv': is_tv,
|
'is_tv': is_tv,
|
||||||
'subtitle_file': subtitle_file,
|
'subtitle_file': subtitle_file,
|
||||||
'media_context': media_context
|
'effective_audio_language': effective_audio_language
|
||||||
})
|
})
|
||||||
consecutive_failures += 1
|
consecutive_failures += 1
|
||||||
if consecutive_failures >= max_consecutive:
|
if consecutive_failures >= max_consecutive:
|
||||||
@ -652,7 +504,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
_save_successful_encoding(
|
_save_successful_encoding(
|
||||||
file, temp_input, temp_output, orig_size, out_size,
|
file, temp_input, temp_output, orig_size, out_size,
|
||||||
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
||||||
file_cq, tracker_file, folder, is_tv, suffix, config, test_mode, subtitle_file, travel_output_folder, replace_file, wait_seconds, media_context
|
file_cq, tracker_file, folder, is_tv, suffix, config, test_mode, subtitle_file, travel_output_folder, replace_file, wait_seconds, combined_suffix
|
||||||
)
|
)
|
||||||
|
|
||||||
# In test mode, stop after first successful file
|
# In test mode, stop after first successful file
|
||||||
@ -705,8 +557,8 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
file_data['res_width'], file_data['res_height'],
|
file_data['res_width'], file_data['res_height'],
|
||||||
file_data['src_width'], file_data['src_height'],
|
file_data['src_width'], file_data['src_height'],
|
||||||
filter_flags, audio_config, "Bitrate", bitrate_config, file_data.get('encoder', encoder),
|
filter_flags, audio_config, "Bitrate", bitrate_config, file_data.get('encoder', encoder),
|
||||||
[file_data.get('subtitle_file')] if file_data.get('subtitle_file') else None, audio_language, None, test_mode, strip_all_titles,
|
[file_data.get('subtitle_file')] if file_data.get('subtitle_file') else None, file_data.get('effective_audio_language'), None, test_mode, strip_all_titles,
|
||||||
file_data.get('src_bit_depth'), unforce_subs, no_encode
|
file_data.get('src_bit_depth'), unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if bitrate also failed
|
# Check if bitrate also failed
|
||||||
@ -730,8 +582,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
file_data['res_width'], file_data['res_height'],
|
file_data['res_width'], file_data['res_height'],
|
||||||
file_data['file_cq'], tracker_file,
|
file_data['file_cq'], tracker_file,
|
||||||
folder, file_data['is_tv'], suffix, config, False,
|
folder, file_data['is_tv'], suffix, config, False,
|
||||||
file_data.get('subtitle_file'), travel_output_folder, replace_file, wait_seconds,
|
file_data.get('subtitle_file'), travel_output_folder, replace_file, wait_seconds, combined_suffix
|
||||||
file_data.get('media_context')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
@ -780,12 +631,9 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
|||||||
|
|
||||||
def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size,
|
def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size,
|
||||||
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
||||||
file_cq, tracker_file, folder, is_tv, suffix, config=None, test_mode=False, subtitle_file=None, travel_output_folder=None, replace_file: bool = False, wait_seconds: int = 0, media_context: dict = None):
|
file_cq, tracker_file, folder, is_tv, suffix, config=None, test_mode=False, subtitle_file=None, travel_output_folder=None, replace_file: bool = False, wait_seconds: int = 0, combined_suffix: str = None):
|
||||||
"""Helper function to save successfully encoded files with [EHX] tag and clean up subtitle files."""
|
"""Helper function to save successfully encoded files with [EHX] tag and clean up subtitle files."""
|
||||||
|
|
||||||
if media_context is None:
|
|
||||||
media_context = {}
|
|
||||||
|
|
||||||
# In test mode, show ratio and skip file move/cleanup
|
# In test mode, show ratio and skip file move/cleanup
|
||||||
if test_mode:
|
if test_mode:
|
||||||
orig_size_mb = round(orig_size / 1e6, 2)
|
orig_size_mb = round(orig_size / 1e6, 2)
|
||||||
@ -801,21 +649,24 @@ def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size
|
|||||||
print(f"Method: {method} (CQ={file_cq if method == 'CQ' else 'N/A'})")
|
print(f"Method: {method} (CQ={file_cq if method == 'CQ' else 'N/A'})")
|
||||||
print(f"{'='*60}")
|
print(f"{'='*60}")
|
||||||
print(f"📁 Encoded file location: {temp_output}")
|
print(f"📁 Encoded file location: {temp_output}")
|
||||||
logger.info(f"TEST MODE - File: {file.name} | Ratio: {percentage}% | Method: {method}", extra=media_context)
|
logger.info(f"TEST MODE - File: {file.name} | Ratio: {percentage}% | Method: {method}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if file is in a Featurettes folder - if so, remove suffix from destination filename
|
# Check if file is in a Featurettes folder - if so, remove suffix from destination filename
|
||||||
folder_parts = [p.lower() for p in file.parent.parts]
|
folder_parts = [p.lower() for p in file.parent.parts]
|
||||||
is_featurette = "featurettes" in folder_parts
|
is_featurette = "featurettes" in folder_parts
|
||||||
|
|
||||||
|
# Use provided combined_suffix if available, otherwise use regular suffix
|
||||||
|
effective_suffix = combined_suffix if combined_suffix else suffix
|
||||||
|
|
||||||
if replace_file:
|
if replace_file:
|
||||||
# Use original filename (no suffix)
|
# Use original filename (no suffix)
|
||||||
dest_file = file.parent / file.name
|
dest_file = file.parent / file.name
|
||||||
elif is_featurette:
|
elif is_featurette:
|
||||||
# Remove suffix from temp_output.name for Featurettes
|
# Remove effective suffix from temp_output.name for Featurettes
|
||||||
output_name = temp_output.name
|
output_name = temp_output.name
|
||||||
if suffix in output_name:
|
if effective_suffix in output_name:
|
||||||
output_name = output_name.replace(suffix, "")
|
output_name = output_name.replace(effective_suffix, "")
|
||||||
dest_file = file.parent / output_name
|
dest_file = file.parent / output_name
|
||||||
else:
|
else:
|
||||||
dest_file = file.parent / temp_output.name
|
dest_file = file.parent / temp_output.name
|
||||||
@ -828,11 +679,11 @@ def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size
|
|||||||
travel_dest_dir.mkdir(parents=True, exist_ok=True)
|
travel_dest_dir.mkdir(parents=True, exist_ok=True)
|
||||||
dest_file = travel_dest_dir / temp_output.name
|
dest_file = travel_dest_dir / temp_output.name
|
||||||
print(f"🧳 Travel mode: Moving to {dest_file}")
|
print(f"🧳 Travel mode: Moving to {dest_file}")
|
||||||
logger.info(f"Travel mode destination: {dest_file}", extra=media_context)
|
logger.info(f"Travel mode destination: {dest_file}")
|
||||||
|
|
||||||
shutil.move(temp_output, dest_file)
|
shutil.move(temp_output, dest_file)
|
||||||
print(f"🚚 Moved {temp_output.name} → {dest_file.name}")
|
print(f"🚚 Moved {temp_output.name} → {dest_file.name}")
|
||||||
logger.info(f"Moved {temp_output.name} → {dest_file.name}", extra=media_context)
|
logger.info(f"Moved {temp_output.name} → {dest_file.name}")
|
||||||
|
|
||||||
# Classify file type based on folder (folder_parts already defined earlier)
|
# Classify file type based on folder (folder_parts already defined earlier)
|
||||||
if "tv" in folder_parts:
|
if "tv" in folder_parts:
|
||||||
@ -871,11 +722,10 @@ def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Enhanced logging with all conversion details
|
# Enhanced logging with all conversion details
|
||||||
log_context = {**media_context, "method": method, "original_size_mb": orig_size_mb, "output_size_mb": proc_size_mb, "reduction_pct": 100 - percentage}
|
logger.info(f"\n✅ CONVERSION COMPLETE: {dest_file.name}")
|
||||||
logger.info(f"✅ CONVERSION COMPLETE: {dest_file.name}", extra=log_context)
|
logger.info(f" Type: {f_type.upper()} | Show: {show}")
|
||||||
logger.info(f" Type: {f_type.upper()} | Show: {show}", extra=log_context)
|
logger.info(f" Size: {orig_size_mb}MB → {proc_size_mb}MB ({percentage}% of original, {100-percentage:.1f}% reduction)")
|
||||||
logger.info(f" Size: {orig_size_mb}MB → {proc_size_mb}MB ({percentage}% of original, {100-percentage:.1f}% reduction)", extra=log_context)
|
logger.info(f" Method: {method} | Status: SUCCESS")
|
||||||
logger.info(f" Method: {method} | Status: SUCCESS", extra=log_context)
|
|
||||||
print(f"📝 Logged conversion: {dest_file.name} ({percentage}%), method={method}")
|
print(f"📝 Logged conversion: {dest_file.name} ({percentage}%), method={method}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -883,9 +733,9 @@ def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size
|
|||||||
|
|
||||||
# Keep original file if in travel mode, replace mode, or if in Featurettes folder
|
# Keep original file if in travel mode, replace mode, or if in Featurettes folder
|
||||||
if travel_output_folder:
|
if travel_output_folder:
|
||||||
logger.info(f"Travel mode: Kept original file {file.name}", extra=media_context)
|
logger.info(f"Travel mode: Kept original file {file.name}")
|
||||||
elif replace_file:
|
elif replace_file:
|
||||||
logger.info(f"Replace mode: Original file has been replaced with processed version at {file.name}", extra=media_context)
|
logger.info(f"Replace mode: Original file has been replaced with processed version at {file.name}")
|
||||||
elif not is_featurette:
|
elif not is_featurette:
|
||||||
file.unlink()
|
file.unlink()
|
||||||
logger.info(f"Deleted original and processing copy for {file.name}")
|
logger.info(f"Deleted original and processing copy for {file.name}")
|
||||||
|
|||||||
@ -230,3 +230,42 @@ def has_forced_subtitles(input_file: Path) -> bool:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to check forced subtitles for {input_file.name}: {e}")
|
logger.warning(f"Failed to check forced subtitles for {input_file.name}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def calculate_crop_dimensions(src_height: int, target_height: int) -> dict:
|
||||||
|
"""
|
||||||
|
Calculate crop dimensions to center-crop video to target height.
|
||||||
|
Maintains width, crops from top and bottom equally.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
src_height: Source video height in pixels
|
||||||
|
target_height: Target crop height in pixels
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict with:
|
||||||
|
- "ffmpeg_filter": FFmpeg crop filter string or empty if no crop needed
|
||||||
|
- "crop_top": Pixels to crop from top
|
||||||
|
- "crop_bottom": Pixels to crop from bottom
|
||||||
|
"""
|
||||||
|
if target_height >= src_height or target_height <= 0:
|
||||||
|
return {
|
||||||
|
"ffmpeg_filter": "",
|
||||||
|
"crop_top": 0,
|
||||||
|
"crop_bottom": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate pixels to remove total
|
||||||
|
pixels_to_remove = src_height - target_height
|
||||||
|
|
||||||
|
# Crop equally from top and bottom (centered crop)
|
||||||
|
crop_amount = pixels_to_remove // 2
|
||||||
|
|
||||||
|
# Note: FFmpeg crop filter is crop=width:height:x:y
|
||||||
|
# We assume width stays the same (1920), and y is the vertical offset (crop_amount)
|
||||||
|
# For 1920x1080 -> 1920x816: crop=1920:816:0:132
|
||||||
|
# where 132 = (1080 - 816) / 2
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ffmpeg_filter": f"crop=-2:{target_height}:0:{crop_amount}",
|
||||||
|
"crop_top": crop_amount,
|
||||||
|
"crop_bottom": crop_amount
|
||||||
|
}
|
||||||
10
dropout_paths.txt
Normal file
10
dropout_paths.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"P:\tv\Adventuring Academy" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Dimension 20's Adventuring Party" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Dimension 20" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Crowd Control" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Game Changer" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Make Some Noise" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Parlor Room" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Smartypants" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Um, Actually" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Very Important People" --title-suffix " WebRip-1080p"
|
||||||
@ -1,832 +0,0 @@
|
|||||||
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
GUI Path Manager for Batch Video Transcoder
|
|
||||||
Allows easy browsing of folders and appending to paths.txt with encoding options.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import tkinter as tk
|
|
||||||
from tkinter import ttk, messagebox, filedialog
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
from core.config_helper import load_config_xml
|
|
||||||
from core.logger_helper import setup_logger
|
|
||||||
|
|
||||||
logger = setup_logger(Path(__file__).parent.parent / "logs")
|
|
||||||
|
|
||||||
class PathManagerGUI:
|
|
||||||
def __init__(self, root):
|
|
||||||
self.root = root
|
|
||||||
self.root.title("Batch Transcoder - Path Manager")
|
|
||||||
self.root.geometry("1100x700")
|
|
||||||
|
|
||||||
# Load config
|
|
||||||
config_path = Path(__file__).parent.parent / "config.xml"
|
|
||||||
self.config = load_config_xml(config_path)
|
|
||||||
self.path_mappings = self.config.get("path_mappings", {})
|
|
||||||
|
|
||||||
# Paths file
|
|
||||||
self.paths_file = Path(__file__).parent.parent / "paths.txt"
|
|
||||||
self.transcode_bat = Path(__file__).parent.parent / "transcode.bat"
|
|
||||||
|
|
||||||
# Current selected folder
|
|
||||||
self.selected_folder = None
|
|
||||||
self.current_category = None
|
|
||||||
self.recently_added = None # Track recently added folder for highlighting
|
|
||||||
self.status_timer = None # Track status message timer
|
|
||||||
self.added_folders = set() # Folders that are in paths.txt
|
|
||||||
|
|
||||||
# Cache for folder data - split per category
|
|
||||||
self.cache_dir = Path(__file__).parent.parent / ".cache"
|
|
||||||
self.cache_dir.mkdir(exist_ok=True)
|
|
||||||
self.folder_cache = {} # Only current category in memory: {folder_path: size}
|
|
||||||
self.scan_in_progress = False
|
|
||||||
self.scanned_categories = set() # Track which categories have been scanned
|
|
||||||
|
|
||||||
# Lazy loading
|
|
||||||
self.all_folders = [] # All folders for current category
|
|
||||||
self.loaded_items = 0 # How many items are currently loaded
|
|
||||||
self.items_per_batch = 100 # Load 100 items at a time
|
|
||||||
|
|
||||||
# Load existing paths
|
|
||||||
self._load_existing_paths()
|
|
||||||
|
|
||||||
# Build UI
|
|
||||||
self._build_ui()
|
|
||||||
|
|
||||||
# Handle window close
|
|
||||||
self.root.protocol("WM_DELETE_WINDOW", self._on_closing)
|
|
||||||
|
|
||||||
def _build_ui(self):
|
|
||||||
"""Build the GUI layout."""
|
|
||||||
# Top frame for category selection and transcode launcher
|
|
||||||
top_frame = ttk.Frame(self.root)
|
|
||||||
top_frame.pack(fill=tk.X, padx=10, pady=10)
|
|
||||||
|
|
||||||
left_top = ttk.Frame(top_frame)
|
|
||||||
left_top.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
|
||||||
|
|
||||||
ttk.Label(left_top, text="Category:").pack(side=tk.LEFT, padx=5)
|
|
||||||
|
|
||||||
self.category_var = tk.StringVar(value="tv")
|
|
||||||
categories = ["tv", "anime", "movies"]
|
|
||||||
for cat in categories:
|
|
||||||
ttk.Radiobutton(
|
|
||||||
left_top, text=cat.upper(), variable=self.category_var,
|
|
||||||
value=cat, command=self._on_category_change
|
|
||||||
).pack(side=tk.LEFT, padx=5)
|
|
||||||
|
|
||||||
ttk.Button(left_top, text="Refresh", command=self._refresh_with_cache_clear).pack(side=tk.LEFT, padx=5)
|
|
||||||
|
|
||||||
# Right side of top frame - transcode launcher
|
|
||||||
right_top = ttk.Frame(top_frame)
|
|
||||||
right_top.pack(side=tk.RIGHT)
|
|
||||||
|
|
||||||
if self.transcode_bat.exists():
|
|
||||||
ttk.Button(
|
|
||||||
right_top, text="▶ Run transcode.bat", command=self._run_transcode
|
|
||||||
).pack(side=tk.RIGHT, padx=5)
|
|
||||||
|
|
||||||
# Main content frame
|
|
||||||
main_frame = ttk.Frame(self.root)
|
|
||||||
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
||||||
|
|
||||||
# Left side - folder tree
|
|
||||||
left_frame = ttk.LabelFrame(main_frame, text="Folders (sorted by size)")
|
|
||||||
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
|
|
||||||
|
|
||||||
# Treeview for folders with add button column
|
|
||||||
self.tree = ttk.Treeview(left_frame, columns=("size", "add", "remove"), height=20)
|
|
||||||
self.tree.column("#0", width=180)
|
|
||||||
self.tree.column("size", width=80)
|
|
||||||
self.tree.column("add", width=50)
|
|
||||||
self.tree.column("remove", width=50)
|
|
||||||
self.tree.heading("#0", text="Folder Name")
|
|
||||||
self.tree.heading("size", text="Size")
|
|
||||||
self.tree.heading("add", text="Add")
|
|
||||||
self.tree.heading("remove", text="Remove")
|
|
||||||
|
|
||||||
scrollbar = ttk.Scrollbar(left_frame, orient=tk.VERTICAL, command=self._on_scrollbar)
|
|
||||||
self.tree.configure(yscroll=scrollbar.set)
|
|
||||||
|
|
||||||
self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
||||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
||||||
|
|
||||||
# Configure tags for folder status
|
|
||||||
self.tree.tag_configure("added", background="#90EE90") # Light green for added
|
|
||||||
self.tree.tag_configure("not_added", background="white") # White for not added
|
|
||||||
self.tree.tag_configure("recently_added", background="#FFD700") # Gold for recently added
|
|
||||||
|
|
||||||
self.tree.bind("<Double-1>", self._on_folder_expand)
|
|
||||||
self.tree.bind("<<TreeviewSelect>>", self._on_folder_select)
|
|
||||||
self.tree.bind("<Button-1>", self._on_tree_click)
|
|
||||||
|
|
||||||
# Right side - options and preview
|
|
||||||
right_frame = ttk.LabelFrame(main_frame, text="Encoding Options & Preview")
|
|
||||||
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
|
|
||||||
|
|
||||||
# Mode selection
|
|
||||||
mode_frame = ttk.LabelFrame(right_frame, text="Mode (--m)")
|
|
||||||
mode_frame.pack(fill=tk.X, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.mode_var = tk.StringVar(value="default")
|
|
||||||
for mode in ["default", "cq", "bitrate"]:
|
|
||||||
ttk.Radiobutton(mode_frame, text=mode, variable=self.mode_var, value=mode,
|
|
||||||
command=self._update_preview).pack(anchor=tk.W, padx=5)
|
|
||||||
|
|
||||||
# Resolution selection
|
|
||||||
res_frame = ttk.LabelFrame(right_frame, text="Resolution (--r)")
|
|
||||||
res_frame.pack(fill=tk.X, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.resolution_var = tk.StringVar(value="none")
|
|
||||||
for res in ["none", "480", "720", "1080"]:
|
|
||||||
label = "Auto" if res == "none" else res + "p"
|
|
||||||
ttk.Radiobutton(res_frame, text=label, variable=self.resolution_var, value=res,
|
|
||||||
command=self._update_preview).pack(anchor=tk.W, padx=5)
|
|
||||||
|
|
||||||
# CQ value
|
|
||||||
cq_frame = ttk.LabelFrame(right_frame, text="CQ Value (--cq, optional)")
|
|
||||||
cq_frame.pack(fill=tk.X, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.cq_var = tk.StringVar(value="")
|
|
||||||
cq_entry = ttk.Entry(cq_frame, textvariable=self.cq_var, width=10)
|
|
||||||
cq_entry.pack(anchor=tk.W, padx=5, pady=3)
|
|
||||||
cq_entry.bind("<KeyRelease>", lambda e: self._update_preview())
|
|
||||||
|
|
||||||
# Preview frame
|
|
||||||
preview_frame = ttk.LabelFrame(right_frame, text="Command Preview")
|
|
||||||
preview_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.preview_text = tk.Text(preview_frame, height=8, width=40, wrap=tk.WORD, bg="lightgray")
|
|
||||||
self.preview_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
|
||||||
self.preview_text.config(state=tk.DISABLED)
|
|
||||||
|
|
||||||
# Bottom frame - action buttons and status
|
|
||||||
bottom_frame = ttk.Frame(self.root)
|
|
||||||
bottom_frame.pack(fill=tk.X, padx=10, pady=10)
|
|
||||||
|
|
||||||
button_frame = ttk.Frame(bottom_frame)
|
|
||||||
button_frame.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
ttk.Button(button_frame, text="View paths.txt", command=self._view_paths_file).pack(side=tk.LEFT, padx=5)
|
|
||||||
ttk.Button(button_frame, text="Clear paths.txt", command=self._clear_paths_file).pack(side=tk.LEFT, padx=5)
|
|
||||||
|
|
||||||
# Status label (for silent feedback)
|
|
||||||
self.status_label = ttk.Label(bottom_frame, text="", foreground="green")
|
|
||||||
self.status_label.pack(side=tk.LEFT, padx=10)
|
|
||||||
|
|
||||||
# Load cache and populate initial category
|
|
||||||
self._load_cache()
|
|
||||||
self._refresh_folders(use_cache=True)
|
|
||||||
# Only scan once per category on first view
|
|
||||||
if self.current_category not in self.scanned_categories:
|
|
||||||
self.root.after(100, self._scan_folders_once)
|
|
||||||
|
|
||||||
def _on_category_change(self):
|
|
||||||
"""Handle category radio button change."""
|
|
||||||
self.current_category = self.category_var.get()
|
|
||||||
# Load cache for this category
|
|
||||||
self._load_cache()
|
|
||||||
# Show cached data first
|
|
||||||
self._refresh_folders(use_cache=True)
|
|
||||||
# Only scan once per category on first view
|
|
||||||
if self.current_category not in self.scanned_categories:
|
|
||||||
self.root.after(100, self._scan_folders_once)
|
|
||||||
|
|
||||||
def _load_cache(self):
|
|
||||||
"""Load folder cache for current category from disk (lazy)."""
|
|
||||||
category = self.category_var.get()
|
|
||||||
cache_file = self.cache_dir / f".cache_{category}.json"
|
|
||||||
|
|
||||||
self.folder_cache.clear()
|
|
||||||
|
|
||||||
# Don't fully load cache yet - just verify it exists
|
|
||||||
if not cache_file.exists():
|
|
||||||
logger.info(f"No cache file for {category}")
|
|
||||||
else:
|
|
||||||
logger.info(f"Cache file exists for {category}")
|
|
||||||
|
|
||||||
def _parse_cache_lazily(self, limit=None):
|
|
||||||
"""Parse cache file lazily and return folders."""
|
|
||||||
category = self.category_var.get()
|
|
||||||
cache_file = self.cache_dir / f".cache_{category}.json"
|
|
||||||
|
|
||||||
folders = []
|
|
||||||
|
|
||||||
if cache_file.exists():
|
|
||||||
try:
|
|
||||||
with open(cache_file, "r", encoding="utf-8") as f:
|
|
||||||
cache_dict = json.load(f)
|
|
||||||
|
|
||||||
# Convert to list and sort
|
|
||||||
for folder_path_str, size in cache_dict.items():
|
|
||||||
folder_path = Path(folder_path_str)
|
|
||||||
if folder_path.exists():
|
|
||||||
folders.append((folder_path.name, folder_path, size))
|
|
||||||
|
|
||||||
# Early exit if limit reached
|
|
||||||
if limit and len(folders) >= limit:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Sort by size descending (only what we loaded)
|
|
||||||
folders.sort(key=lambda x: x[2], reverse=True)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to parse cache: {e}")
|
|
||||||
|
|
||||||
return folders
|
|
||||||
|
|
||||||
def _save_cache(self):
|
|
||||||
"""Save current category's folder cache to disk."""
|
|
||||||
category = self.category_var.get()
|
|
||||||
cache_file = self.cache_dir / f".cache_{category}.json"
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(cache_file, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(self.folder_cache, f, indent=2)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to save {category} cache: {e}")
|
|
||||||
|
|
||||||
def _refresh_with_cache_clear(self):
|
|
||||||
"""Refresh and clear cache to force full scan."""
|
|
||||||
category = self.category_var.get()
|
|
||||||
cache_file = self.cache_dir / f".cache_{category}.json"
|
|
||||||
|
|
||||||
# Delete cache file for this category
|
|
||||||
if cache_file.exists():
|
|
||||||
cache_file.unlink()
|
|
||||||
|
|
||||||
self.folder_cache.clear()
|
|
||||||
self.scanned_categories.discard(category) # Reset so it will scan again
|
|
||||||
self._refresh_folders(use_cache=False)
|
|
||||||
|
|
||||||
def _scan_folders_once(self):
|
|
||||||
"""Scan folders once per category on first load."""
|
|
||||||
if self.scan_in_progress:
|
|
||||||
return
|
|
||||||
|
|
||||||
category = self.category_var.get()
|
|
||||||
if category in self.scanned_categories:
|
|
||||||
return # Already scanned this category
|
|
||||||
|
|
||||||
self.scan_in_progress = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
category_mapping = {
|
|
||||||
"tv": "P:\\tv",
|
|
||||||
"anime": "P:\\anime",
|
|
||||||
"movies": "P:\\movies"
|
|
||||||
}
|
|
||||||
|
|
||||||
base_key = category_mapping.get(category)
|
|
||||||
if not base_key or base_key not in self.path_mappings:
|
|
||||||
return
|
|
||||||
|
|
||||||
base_path = Path(base_key)
|
|
||||||
if not base_path.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
# Scan folders and update cache
|
|
||||||
new_cache = {}
|
|
||||||
for entry in os.scandir(base_path):
|
|
||||||
if entry.is_dir(follow_symlinks=False):
|
|
||||||
size = self._get_folder_size(Path(entry))
|
|
||||||
new_cache[str(Path(entry))] = size
|
|
||||||
|
|
||||||
# Update cache and save
|
|
||||||
self.folder_cache = new_cache
|
|
||||||
self._save_cache()
|
|
||||||
self.scanned_categories.add(category)
|
|
||||||
|
|
||||||
# Update UI if still on same category
|
|
||||||
if self.category_var.get() == category:
|
|
||||||
self._refresh_folders(use_cache=True)
|
|
||||||
finally:
|
|
||||||
self.scan_in_progress = False
|
|
||||||
|
|
||||||
def _scan_folders_background(self):
|
|
||||||
"""Scan folders in background and update cache."""
|
|
||||||
if self.scan_in_progress:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.scan_in_progress = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
category = self.category_var.get()
|
|
||||||
category_mapping = {
|
|
||||||
"tv": "P:\\tv",
|
|
||||||
"anime": "P:\\anime",
|
|
||||||
"movies": "P:\\movies"
|
|
||||||
}
|
|
||||||
|
|
||||||
base_key = category_mapping.get(category)
|
|
||||||
if not base_key or base_key not in self.path_mappings:
|
|
||||||
return
|
|
||||||
|
|
||||||
base_path = Path(base_key)
|
|
||||||
if not base_path.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
# Scan folders and update cache
|
|
||||||
new_cache = {}
|
|
||||||
for entry in os.scandir(base_path):
|
|
||||||
if entry.is_dir(follow_symlinks=False):
|
|
||||||
size = self._get_folder_size(Path(entry))
|
|
||||||
new_cache[str(Path(entry))] = size
|
|
||||||
|
|
||||||
# Update cache and save
|
|
||||||
self.folder_cache[category] = new_cache
|
|
||||||
self._save_cache()
|
|
||||||
|
|
||||||
# Update UI if still on same category
|
|
||||||
if self.category_var.get() == category:
|
|
||||||
self._refresh_folders(use_cache=True)
|
|
||||||
finally:
|
|
||||||
self.scan_in_progress = False
|
|
||||||
# Schedule next continuous scan
|
|
||||||
self.background_scan_timer = self.root.after(
|
|
||||||
self.background_scan_interval,
|
|
||||||
self._continuous_background_scan
|
|
||||||
)
|
|
||||||
# Schedule next continuous scan
|
|
||||||
self.background_scan_timer = self.root.after(
|
|
||||||
self.background_scan_interval,
|
|
||||||
self._continuous_background_scan
|
|
||||||
)
|
|
||||||
|
|
||||||
def _load_existing_paths(self):
|
|
||||||
"""Load existing paths from paths.txt and extract folder paths."""
|
|
||||||
self.added_folders.clear()
|
|
||||||
|
|
||||||
if not self.paths_file.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(self.paths_file, "r", encoding="utf-8") as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Extract the path (last argument in the command)
|
|
||||||
# Format: --m mode --r res --cq val "path" or just "path"
|
|
||||||
# Find all quoted strings
|
|
||||||
matches = re.findall(r'"([^"]*)"', line)
|
|
||||||
if matches:
|
|
||||||
# Last quoted string is the path
|
|
||||||
path = matches[-1]
|
|
||||||
self.added_folders.add(path)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to load existing paths: {e}")
|
|
||||||
|
|
||||||
def _get_folder_size(self, path: Path) -> int:
|
|
||||||
"""Calculate total size of folder in bytes."""
|
|
||||||
total = 0
|
|
||||||
try:
|
|
||||||
for entry in os.scandir(path):
|
|
||||||
if entry.is_file(follow_symlinks=False):
|
|
||||||
total += entry.stat().st_size
|
|
||||||
elif entry.is_dir(follow_symlinks=False):
|
|
||||||
total += self._get_folder_size(Path(entry))
|
|
||||||
except PermissionError:
|
|
||||||
pass
|
|
||||||
return total
|
|
||||||
|
|
||||||
def _format_size(self, bytes_size: int) -> str:
|
|
||||||
"""Format bytes to human readable size."""
|
|
||||||
for unit in ["B", "KB", "MB", "GB", "TB"]:
|
|
||||||
if bytes_size < 1024:
|
|
||||||
return f"{bytes_size:.1f} {unit}"
|
|
||||||
bytes_size /= 1024
|
|
||||||
return f"{bytes_size:.1f} PB"
|
|
||||||
|
|
||||||
def _refresh_folders(self, use_cache=False):
|
|
||||||
"""Refresh the folder tree from cache or disk."""
|
|
||||||
# Clear existing items
|
|
||||||
for item in self.tree.get_children():
|
|
||||||
self.tree.delete(item)
|
|
||||||
|
|
||||||
self.all_folders = []
|
|
||||||
self.loaded_items = 0
|
|
||||||
|
|
||||||
category = self.category_var.get()
|
|
||||||
|
|
||||||
# Map category to path mapping key
|
|
||||||
category_mapping = {
|
|
||||||
"tv": "P:\\tv",
|
|
||||||
"anime": "P:\\anime",
|
|
||||||
"movies": "P:\\movies"
|
|
||||||
}
|
|
||||||
|
|
||||||
base_key = category_mapping.get(category)
|
|
||||||
if not base_key or base_key not in self.path_mappings:
|
|
||||||
messagebox.showwarning("Info", f"No mapping found for {category}")
|
|
||||||
return
|
|
||||||
|
|
||||||
base_path = Path(base_key)
|
|
||||||
|
|
||||||
# Check if path exists
|
|
||||||
if not base_path.exists():
|
|
||||||
messagebox.showerror("Error", f"Path not found: {base_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get folders from cache or disk
|
|
||||||
if use_cache:
|
|
||||||
# Parse cache lazily - only load what we need initially
|
|
||||||
folders = self._parse_cache_lazily(limit=None) # Get all but parse efficiently
|
|
||||||
else:
|
|
||||||
# Scan from disk
|
|
||||||
folders = []
|
|
||||||
try:
|
|
||||||
for entry in os.scandir(base_path):
|
|
||||||
if entry.is_dir(follow_symlinks=False):
|
|
||||||
size = self._get_folder_size(Path(entry))
|
|
||||||
folders.append((entry.name, Path(entry), size))
|
|
||||||
except PermissionError:
|
|
||||||
messagebox.showerror("Error", f"Permission denied accessing {base_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Update cache with fresh scan
|
|
||||||
cache_dict = {str(f[1]): f[2] for f in folders}
|
|
||||||
self.folder_cache = cache_dict
|
|
||||||
self._save_cache()
|
|
||||||
|
|
||||||
# Sort by size descending
|
|
||||||
folders.sort(key=lambda x: x[2], reverse=True)
|
|
||||||
|
|
||||||
# Store all folders and load first batch only
|
|
||||||
self.all_folders = folders
|
|
||||||
self._load_more_items()
|
|
||||||
|
|
||||||
def _on_folder_expand(self, event):
|
|
||||||
"""Handle folder double-click to show contents."""
|
|
||||||
selection = self.tree.selection()
|
|
||||||
if not selection:
|
|
||||||
return
|
|
||||||
|
|
||||||
item = selection[0]
|
|
||||||
tags = self.tree.item(item, "tags")
|
|
||||||
|
|
||||||
if not tags:
|
|
||||||
return
|
|
||||||
|
|
||||||
folder_path = Path(tags[0])
|
|
||||||
|
|
||||||
# Check if already expanded
|
|
||||||
if self.tree.get_children(item):
|
|
||||||
# Toggle: remove children
|
|
||||||
for child in self.tree.get_children(item):
|
|
||||||
self.tree.delete(child)
|
|
||||||
else:
|
|
||||||
# Add file/folder contents
|
|
||||||
try:
|
|
||||||
entries = []
|
|
||||||
for entry in os.scandir(folder_path):
|
|
||||||
if entry.is_file():
|
|
||||||
size = entry.stat().st_size
|
|
||||||
entries.append((entry.name, "File", size))
|
|
||||||
elif entry.is_dir():
|
|
||||||
size = self._get_folder_size(Path(entry))
|
|
||||||
entries.append((entry.name, "Folder", size))
|
|
||||||
|
|
||||||
# Sort by size descending
|
|
||||||
entries.sort(key=lambda x: x[2], reverse=True)
|
|
||||||
|
|
||||||
for name, type_str, size in entries:
|
|
||||||
size_str = self._format_size(size)
|
|
||||||
self.tree.insert(item, "end", text=f"[{type_str}] {name}", values=(size_str,))
|
|
||||||
except PermissionError:
|
|
||||||
messagebox.showerror("Error", f"Permission denied accessing {folder_path}")
|
|
||||||
|
|
||||||
def _on_folder_select(self, event):
|
|
||||||
"""Handle folder selection to update preview."""
|
|
||||||
selection = self.tree.selection()
|
|
||||||
if not selection:
|
|
||||||
return
|
|
||||||
|
|
||||||
item = selection[0]
|
|
||||||
tags = self.tree.item(item, "tags")
|
|
||||||
|
|
||||||
if tags:
|
|
||||||
self.selected_folder = tags[0]
|
|
||||||
self._update_preview()
|
|
||||||
|
|
||||||
def _on_tree_click(self, event):
|
|
||||||
"""Handle click on '+' or '-' button in add column."""
|
|
||||||
item = self.tree.identify("item", event.x, event.y)
|
|
||||||
column = self.tree.identify_column(event.x) # Only takes x coordinate
|
|
||||||
|
|
||||||
# Column #2 is the "add" column (columns are #0=name, #1=size, #2=add, #3=remove)
|
|
||||||
if item and column == "#2":
|
|
||||||
tags = self.tree.item(item, "tags")
|
|
||||||
if tags:
|
|
||||||
folder_path = tags[0]
|
|
||||||
values = self.tree.item(item, "values")
|
|
||||||
if len(values) > 1:
|
|
||||||
button_text = values[1] # Get button text
|
|
||||||
|
|
||||||
if "[+]" in button_text:
|
|
||||||
# Immediately update UI for snappy response
|
|
||||||
size_val = values[0]
|
|
||||||
self.tree.item(item, values=(size_val, "", "[-]"), tags=(folder_path, "added"))
|
|
||||||
|
|
||||||
# Add to paths.txt asynchronously
|
|
||||||
self.selected_folder = folder_path
|
|
||||||
self.root.after(0, self._add_to_paths_file_async, folder_path)
|
|
||||||
|
|
||||||
# Column #3 is the "remove" column
|
|
||||||
elif item and column == "#3":
|
|
||||||
tags = self.tree.item(item, "tags")
|
|
||||||
if tags:
|
|
||||||
folder_path = tags[0]
|
|
||||||
|
|
||||||
# Immediately update UI for snappy response
|
|
||||||
values = self.tree.item(item, "values")
|
|
||||||
size_val = values[0]
|
|
||||||
self.tree.item(item, values=(size_val, "[+]", ""), tags=(folder_path, "not_added"))
|
|
||||||
|
|
||||||
# Remove from paths.txt asynchronously
|
|
||||||
self.root.after(0, self._remove_from_paths_file_async, folder_path)
|
|
||||||
|
|
||||||
def _add_to_paths_file_async(self, folder_path):
|
|
||||||
"""Add to paths.txt without blocking UI."""
|
|
||||||
self.selected_folder = folder_path
|
|
||||||
self._add_to_paths_file()
|
|
||||||
# Silently reload in background
|
|
||||||
self._load_existing_paths()
|
|
||||||
|
|
||||||
def _remove_from_paths_file_async(self, folder_path):
|
|
||||||
"""Remove from paths.txt without blocking UI."""
|
|
||||||
self._remove_from_paths_file(folder_path)
|
|
||||||
|
|
||||||
def _update_preview(self):
|
|
||||||
"""Update the command preview."""
|
|
||||||
if not self.selected_folder:
|
|
||||||
preview_text = "No folder selected"
|
|
||||||
else:
|
|
||||||
folder_path = self.selected_folder
|
|
||||||
|
|
||||||
# Build command
|
|
||||||
cmd_parts = ['py main.py']
|
|
||||||
|
|
||||||
# Add mode if not default
|
|
||||||
mode = self.mode_var.get()
|
|
||||||
if mode != "default":
|
|
||||||
cmd_parts.append(f'--m {mode}')
|
|
||||||
|
|
||||||
# Add resolution if specified
|
|
||||||
resolution = self.resolution_var.get()
|
|
||||||
if resolution != "none":
|
|
||||||
cmd_parts.append(f'--r {resolution}')
|
|
||||||
|
|
||||||
# Add CQ if specified
|
|
||||||
cq = self.cq_var.get().strip()
|
|
||||||
if cq:
|
|
||||||
cmd_parts.append(f'--cq {cq}')
|
|
||||||
|
|
||||||
# Add path
|
|
||||||
cmd_parts.append(f'"{folder_path}"')
|
|
||||||
|
|
||||||
preview_text = " ".join(cmd_parts)
|
|
||||||
|
|
||||||
self.preview_text.config(state=tk.NORMAL)
|
|
||||||
self.preview_text.delete("1.0", tk.END)
|
|
||||||
self.preview_text.insert("1.0", preview_text)
|
|
||||||
self.preview_text.config(state=tk.DISABLED)
|
|
||||||
|
|
||||||
def _add_to_paths_file(self):
|
|
||||||
"""Append the current command to paths.txt."""
|
|
||||||
if not self.selected_folder:
|
|
||||||
messagebox.showwarning("Warning", "Please select a folder first")
|
|
||||||
return
|
|
||||||
|
|
||||||
folder_path = self.selected_folder
|
|
||||||
|
|
||||||
# Check if already in file
|
|
||||||
if folder_path in self.added_folders:
|
|
||||||
self._show_status(f"Already added: {Path(folder_path).name}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Build command line - start fresh
|
|
||||||
cmd_parts = []
|
|
||||||
|
|
||||||
# Add mode if not default
|
|
||||||
mode = self.mode_var.get()
|
|
||||||
if mode != "default":
|
|
||||||
cmd_parts.append(f'--m {mode}')
|
|
||||||
|
|
||||||
# Add resolution if specified
|
|
||||||
resolution = self.resolution_var.get()
|
|
||||||
if resolution != "none":
|
|
||||||
cmd_parts.append(f'--r {resolution}')
|
|
||||||
|
|
||||||
# Add CQ if specified
|
|
||||||
cq = self.cq_var.get().strip()
|
|
||||||
if cq:
|
|
||||||
cmd_parts.append(f'--cq {cq}')
|
|
||||||
|
|
||||||
# Add folder path
|
|
||||||
cmd_parts.append(f'"{folder_path}"')
|
|
||||||
|
|
||||||
line = " ".join(cmd_parts)
|
|
||||||
|
|
||||||
# Append to paths.txt
|
|
||||||
try:
|
|
||||||
# Check if file exists and has content
|
|
||||||
if self.paths_file.exists() and self.paths_file.stat().st_size > 0:
|
|
||||||
# Read last character to check if it ends with newline
|
|
||||||
with open(self.paths_file, "rb") as f:
|
|
||||||
f.seek(-1, 2) # Seek to last byte
|
|
||||||
last_char = f.read(1)
|
|
||||||
needs_newline = last_char != b'\n'
|
|
||||||
else:
|
|
||||||
needs_newline = False
|
|
||||||
|
|
||||||
# Write to file
|
|
||||||
with open(self.paths_file, "a", encoding="utf-8") as f:
|
|
||||||
if needs_newline:
|
|
||||||
f.write("\n")
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
# Add to tracked set
|
|
||||||
self.added_folders.add(folder_path)
|
|
||||||
|
|
||||||
# Silent success - show status label instead of popup
|
|
||||||
self.recently_added = folder_path
|
|
||||||
self._show_status(f"✓ Added: {Path(folder_path).name}")
|
|
||||||
logger.info(f"Added to paths.txt: {line}")
|
|
||||||
|
|
||||||
# Clear timer if exists
|
|
||||||
if self.status_timer:
|
|
||||||
self.root.after_cancel(self.status_timer)
|
|
||||||
|
|
||||||
# Clear status after 3 seconds
|
|
||||||
self.status_timer = self.root.after(3000, self._clear_status)
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", f"Failed to write to paths.txt: {e}")
|
|
||||||
logger.error(f"Failed to write to paths.txt: {e}")
|
|
||||||
|
|
||||||
def _remove_from_paths_file(self, folder_path):
|
|
||||||
"""Remove a folder from paths.txt."""
|
|
||||||
if not self.paths_file.exists():
|
|
||||||
messagebox.showwarning("Warning", "paths.txt does not exist")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(self.paths_file, "r", encoding="utf-8") as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
|
|
||||||
# Filter out lines containing this folder path
|
|
||||||
new_lines = []
|
|
||||||
found = False
|
|
||||||
for line in lines:
|
|
||||||
if f'"{folder_path}"' in line or f"'{folder_path}'" in line:
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
new_lines.append(line)
|
|
||||||
|
|
||||||
if not found:
|
|
||||||
messagebox.showwarning("Warning", "Path not found in paths.txt")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Write back
|
|
||||||
with open(self.paths_file, "w", encoding="utf-8") as f:
|
|
||||||
f.writelines(new_lines)
|
|
||||||
|
|
||||||
# Remove from tracked set
|
|
||||||
self.added_folders.discard(folder_path)
|
|
||||||
|
|
||||||
self._show_status(f"✓ Removed: {Path(folder_path).name}")
|
|
||||||
logger.info(f"Removed from paths.txt: {folder_path}")
|
|
||||||
|
|
||||||
# Clear timer if exists
|
|
||||||
if self.status_timer:
|
|
||||||
self.root.after_cancel(self.status_timer)
|
|
||||||
|
|
||||||
# Clear status after 3 seconds
|
|
||||||
self.status_timer = self.root.after(3000, self._clear_status)
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", f"Failed to remove from paths.txt: {e}")
|
|
||||||
logger.error(f"Failed to remove from paths.txt: {e}")
|
|
||||||
|
|
||||||
def _show_status(self, message):
|
|
||||||
"""Show status message in label."""
|
|
||||||
self.status_label.config(text=message, foreground="green")
|
|
||||||
|
|
||||||
def _clear_status(self):
|
|
||||||
"""Clear status message after delay."""
|
|
||||||
self.status_label.config(text="")
|
|
||||||
self.status_timer = None
|
|
||||||
|
|
||||||
def _run_transcode(self):
|
|
||||||
"""Launch transcode.bat in a new command window."""
|
|
||||||
if not self.transcode_bat.exists():
|
|
||||||
messagebox.showerror("Error", f"transcode.bat not found at {self.transcode_bat}")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Launch in new cmd window
|
|
||||||
subprocess.Popen(
|
|
||||||
['cmd', '/c', f'"{self.transcode_bat}"'],
|
|
||||||
cwd=str(self.transcode_bat.parent),
|
|
||||||
creationflags=subprocess.CREATE_NEW_CONSOLE
|
|
||||||
)
|
|
||||||
logger.info("Launched transcode.bat")
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", f"Failed to launch transcode.bat: {e}")
|
|
||||||
logger.error(f"Failed to launch transcode.bat: {e}")
|
|
||||||
|
|
||||||
def _view_paths_file(self):
|
|
||||||
"""Open paths.txt in a new window."""
|
|
||||||
if not self.paths_file.exists():
|
|
||||||
messagebox.showinfo("Info", "paths.txt does not exist yet")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(self.paths_file, "r", encoding="utf-8") as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Create new window
|
|
||||||
view_window = tk.Toplevel(self.root)
|
|
||||||
view_window.title("paths.txt")
|
|
||||||
view_window.geometry("800x400")
|
|
||||||
|
|
||||||
text_widget = tk.Text(view_window, wrap=tk.WORD)
|
|
||||||
text_widget.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
||||||
text_widget.insert("1.0", content)
|
|
||||||
|
|
||||||
# Add close button
|
|
||||||
ttk.Button(view_window, text="Close", command=view_window.destroy).pack(pady=5)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", f"Failed to read paths.txt: {e}")
|
|
||||||
|
|
||||||
def _clear_paths_file(self):
|
|
||||||
"""Clear the paths.txt file."""
|
|
||||||
if not self.paths_file.exists():
|
|
||||||
messagebox.showinfo("Info", "paths.txt does not exist")
|
|
||||||
return
|
|
||||||
|
|
||||||
if messagebox.askyesno("Confirm", "Are you sure you want to clear paths.txt?"):
|
|
||||||
try:
|
|
||||||
self.paths_file.write_text("", encoding="utf-8")
|
|
||||||
messagebox.showinfo("Success", "paths.txt has been cleared")
|
|
||||||
logger.info("paths.txt cleared")
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", f"Failed to clear paths.txt: {e}")
|
|
||||||
|
|
||||||
def _on_closing(self):
|
|
||||||
"""Handle window closing - cleanup timers."""
|
|
||||||
self.root.destroy()
|
|
||||||
|
|
||||||
def _on_scrollbar(self, *args):
|
|
||||||
"""Handle scrollbar movement - load more items when scrolling."""
|
|
||||||
self.tree.yview(*args)
|
|
||||||
|
|
||||||
# Check if we need to load more items
|
|
||||||
if self.all_folders and self.loaded_items < len(self.all_folders):
|
|
||||||
# Get scroll position
|
|
||||||
first_visible = self.tree.yview()[0]
|
|
||||||
last_visible = self.tree.yview()[1]
|
|
||||||
|
|
||||||
# If we're past 70% scrolled, load more
|
|
||||||
if last_visible > 0.7:
|
|
||||||
self._load_more_items()
|
|
||||||
|
|
||||||
def _load_more_items(self):
|
|
||||||
"""Load next batch of items into tree."""
|
|
||||||
start = self.loaded_items
|
|
||||||
end = min(start + self.items_per_batch, len(self.all_folders))
|
|
||||||
|
|
||||||
for i in range(start, end):
|
|
||||||
folder_name, folder_path, size = self.all_folders[i]
|
|
||||||
size_str = self._format_size(size)
|
|
||||||
folder_path_str = str(folder_path)
|
|
||||||
|
|
||||||
# Determine button and tag
|
|
||||||
if folder_path_str in self.added_folders:
|
|
||||||
add_btn = ""
|
|
||||||
remove_btn = "[-]"
|
|
||||||
tag = "added"
|
|
||||||
else:
|
|
||||||
add_btn = "[+]"
|
|
||||||
remove_btn = ""
|
|
||||||
tag = "not_added"
|
|
||||||
|
|
||||||
self.tree.insert("", "end", text=folder_name, values=(size_str, add_btn, remove_btn),
|
|
||||||
tags=(folder_path_str, tag))
|
|
||||||
|
|
||||||
self.loaded_items = end
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
root = tk.Tk()
|
|
||||||
app = PathManagerGUI(root)
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
10939
logs/conversion.log
10939
logs/conversion.log
File diff suppressed because it is too large
Load Diff
50508
logs/conversion.log.1
50508
logs/conversion.log.1
File diff suppressed because it is too large
Load Diff
53416
logs/conversion.log.2
53416
logs/conversion.log.2
File diff suppressed because it is too large
Load Diff
27109
logs/conversion.log.3
Normal file
27109
logs/conversion.log.3
Normal file
File diff suppressed because it is too large
Load Diff
@ -103,3 +103,44 @@
|
|||||||
2026-04-09 09:18:43 | Blue mountain state S00E04 Making the Squad.mkv | CQ failed: Size threshold not met (111.3%)
|
2026-04-09 09:18:43 | Blue mountain state S00E04 Making the Squad.mkv | CQ failed: Size threshold not met (111.3%)
|
||||||
2026-04-09 09:41:36 | Blue Mountain State (2010) - S01E05 - There's Only One Second Best (1080p x265 Panda).mkv | CQ failed: Size threshold not met (99.7%)
|
2026-04-09 09:41:36 | Blue Mountain State (2010) - S01E05 - There's Only One Second Best (1080p x265 Panda).mkv | CQ failed: Size threshold not met (99.7%)
|
||||||
2026-04-09 13:31:23 | Malcolm in the Middle (2000) - S02E01 - Traffic Jam (2) (1080p AMZN WEB-DL x265 Silence).mkv | CQ failed: Size threshold not met (98.6%)
|
2026-04-09 13:31:23 | Malcolm in the Middle (2000) - S02E01 - Traffic Jam (2) (1080p AMZN WEB-DL x265 Silence).mkv | CQ failed: Size threshold not met (98.6%)
|
||||||
|
2026-04-16 11:18:35 | Without a Paddle (2004) AVC TrueHD 5.1 Remux-1080p FraMeSToR.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-04-22 22:30:37 | Jury Duty (2023) - S02E01 - Onboarding (1080p AMZN WEB-DL x265 Silence)_new.mkv | Unexpected error: too many values to unpack (expected 7)
|
||||||
|
2026-04-22 22:30:40 | Jury Duty (2023) - S02E02 - Team Building (1080p AMZN WEB-DL x265 Silence)_new.mkv | Unexpected error: too many values to unpack (expected 7)
|
||||||
|
2026-04-22 23:06:42 | Making Of.mkv | CQ failed: Size threshold not met (101.0%)
|
||||||
|
2026-04-22 23:07:00 | Trailer 1.mkv | CQ failed: Size threshold not met (95.3%)
|
||||||
|
2026-04-23 21:23:32 | Euphoria (US) - S03E01 - Andale x265 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (105.1%)
|
||||||
|
2026-04-23 21:30:28 | Euphoria (US) - S03E02 - America My Dream AV1 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (115.3%)
|
||||||
|
2026-04-23 21:31:15 | costumes of euphoria.mkv | CQ failed: Size threshold not met (150.2%)
|
||||||
|
2026-04-24 09:15:19 | Behind the Scenes.mkv | CQ failed: Size threshold not met (121.5%)
|
||||||
|
2026-04-24 09:15:39 | Liam Neeson - Known Action Hero.mkv | CQ failed: Size threshold not met (106.2%)
|
||||||
|
2026-04-26 01:14:50 | Inside “Mayor of Kingstown”.mkv | Unexpected error: 'charmap' codec can't decode byte 0x9d in position 123: character maps to <undefined>
|
||||||
|
2026-04-26 01:15:50 | Perdition꞉ Making “Mayor of Kingstown”.mkv | Unexpected error: 'charmap' codec can't decode byte 0x9d in position 136: character maps to <undefined>
|
||||||
|
2026-04-26 08:46:22 | Winning Time - The Rise of the Lakers Dynasty - S01E01 - The Swan x265 AAC Bluray-1080p RARBG.mp4 | CQ failed: Size threshold not met (106.3%)
|
||||||
|
2026-04-26 08:50:30 | Winning Time - The Rise of the Lakers Dynasty - S01E02 - Is That All There Is x265 AAC Bluray-1080p RARBG.mp4 | CQ failed: Size threshold not met (110.7%)
|
||||||
|
2026-04-26 08:54:21 | Winning Time - The Rise of the Lakers Dynasty - S01E03 - The Good Life x265 AAC Bluray-1080p RARBG.mp4 | CQ failed: Size threshold not met (110.8%)
|
||||||
|
2026-04-26 13:19:46 | Behind the Scenes - Drift Space.mkv | CQ failed: Size threshold not met (117.1%)
|
||||||
|
2026-04-26 13:22:05 | Behind the Scenes - The Digital Artistry of Pacific Rim.mkv | CQ failed: Size threshold not met (159.0%)
|
||||||
|
2026-04-26 13:23:27 | Behind the Scenes - The Shatterdome.mkv | CQ failed: Size threshold not met (158.1%)
|
||||||
|
2026-04-29 16:02:32 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (100.1%)
|
||||||
|
2026-04-29 16:03:27 | Star Wars Andor (2022) - S02E01 - One Year Later (1080p DSNP WEB-DL x265 t3nzin).mkv | Unexpected error: 'charmap' codec can't decode byte 0x8d in position 286: character maps to <undefined>
|
||||||
|
2026-04-29 16:04:08 | Star Wars Andor (2022) - S02E02 - Sagrona Teema (1080p DSNP WEB-DL x265 t3nzin).mkv | Unexpected error: 'charmap' codec can't decode byte 0x8d in position 25: character maps to <undefined>
|
||||||
|
2026-04-30 20:59:09 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (100.1%)
|
||||||
|
2026-04-30 20:59:14 | Star Wars Andor (2022) - S02E01 - One Year Later (1080p DSNP WEB-DL x265 t3nzin).mkv | Unexpected error: 'charmap' codec can't decode byte 0x8d in position 176: character maps to <undefined>
|
||||||
|
2026-04-30 20:59:18 | Star Wars Andor (2022) - S02E02 - Sagrona Teema (1080p DSNP WEB-DL x265 t3nzin).mkv | Unexpected error: 'charmap' codec can't decode byte 0x8d in position 387: character maps to <undefined>
|
||||||
|
2026-04-30 21:02:00 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (100.1%)
|
||||||
|
2026-04-30 21:05:05 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | Unexpected error: Size threshold not met (132.7%)
|
||||||
|
2026-04-30 21:07:37 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | Unexpected error: Size threshold not met (100.1%)
|
||||||
|
2026-04-30 21:31:15 | Andor - S00E01 - A Disney+ Day Special Look x265 EAC3 HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (132.7%)
|
||||||
|
2026-05-12 19:59:11 | Worst Cooks in America - S29E01 - Talented & Terrible - Boot Camp's Got Talent x265 AAC HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (97.7%)
|
||||||
|
2026-05-14 22:16:20 | Shetland - 1x01 - Red Bones (1).mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-14 22:29:03 | Shetland - 1x01 - Red Bones (1).mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-14 22:34:06 | Shetland - 1x01 - Red Bones (1).mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-16 21:24:33 | Rick and Morty - S01E01 - Pilot h265 AAC Bluray-1080p SEPH1.mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-16 21:24:44 | Rick and Morty - S01E02 - Lawnmower Dog h265 AAC Bluray-1080p SEPH1.mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-16 21:24:55 | Rick and Morty - S01E03 - Anatomy Park h265 AAC Bluray-1080p SEPH1.mp4 | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||||
|
2026-05-16 22:16:49 | Rick and Morty - S01E08 - Rixty Minutes h265 AAC Bluray-1080p SEPH1.mp4 | Unexpected error: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\U
|
||||||
|
2026-05-17 01:21:22 | Rick and Morty - S00E180 - The Great Yokai Battle of Akihabara x265 AAC HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (119.4%)
|
||||||
|
2026-05-17 01:22:45 | Rick and Morty - S00E187 - Summer's Sleepover x265 AAC HDTV-1080p MeGusta.mkv | CQ failed: Size threshold not met (127.2%)
|
||||||
|
2026-05-17 14:14:13 | Season 2 - Step Back in Time on Set of “The Gilded Age”.mkv | Unexpected error: 'charmap' codec can't decode byte 0x9d in position 151: character maps to <undefined>
|
||||||
|
2026-05-17 14:14:54 | Designing “The Gilded Age”.mkv | Unexpected error: 'charmap' codec can't decode byte 0x9d in position 122: character maps to <undefined>
|
||||||
|
2026-05-17 16:00:53 | Designing “The Gilded Age”.mkv | Unexpected error: 'charmap' codec can't decode byte 0x9d in position 122: character maps to <undefined>
|
||||||
|
|||||||
609
main.py
609
main.py
@ -6,6 +6,7 @@ Main entry point for batch video encoding with intelligent audio and resolution
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import csv
|
import csv
|
||||||
|
import shlex
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from core.config_helper import load_config_xml
|
from core.config_helper import load_config_xml
|
||||||
@ -64,6 +65,220 @@ def normalize_input_path(input_path: str, path_mappings: dict) -> Path:
|
|||||||
logger.info(f"Using path as-is: {result}")
|
logger.info(f"Using path as-is: {result}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# =============================
|
||||||
|
# BATCH PROCESSING
|
||||||
|
# =============================
|
||||||
|
def parse_batch_file(file_path: Path) -> list:
|
||||||
|
"""
|
||||||
|
Parse batch file (.txt or .csv) and extract paths with optional per-row parameters.
|
||||||
|
|
||||||
|
Formats:
|
||||||
|
- Simple list (.txt): One path per line, optional space-separated parameters
|
||||||
|
Example: P:\movies\Movie1 --r 720 --cq 28
|
||||||
|
- CSV (.csv): First column is path, remaining columns are optional parameters
|
||||||
|
Example: "P:\movies\Movie1","--r 720","--cq 28"
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: Path to batch file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of tuples: [(path_str, params_str), ...]
|
||||||
|
"""
|
||||||
|
batch_items = []
|
||||||
|
|
||||||
|
if file_path.suffix.lower() == ".csv":
|
||||||
|
# CSV format
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
for row_idx, row in enumerate(reader):
|
||||||
|
if not row or not row[0].strip():
|
||||||
|
continue # Skip empty rows
|
||||||
|
|
||||||
|
path_str = row[0].strip()
|
||||||
|
|
||||||
|
# Skip header row (if it starts with "path")
|
||||||
|
if row_idx == 0 and path_str.lower().startswith("path"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Combine remaining columns as parameters
|
||||||
|
params = " ".join(col.strip() for col in row[1:] if col.strip())
|
||||||
|
batch_items.append((path_str, params))
|
||||||
|
else:
|
||||||
|
# Simple list format (.txt or others)
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
# Skip empty lines and comments
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Split path from parameters
|
||||||
|
# Handle quoted paths like: "C:\path with spaces" --r 720
|
||||||
|
if line.startswith('"'):
|
||||||
|
# Find closing quote
|
||||||
|
end_quote = line.find('"', 1)
|
||||||
|
if end_quote != -1:
|
||||||
|
path_str = line[1:end_quote]
|
||||||
|
params = line[end_quote+1:].strip()
|
||||||
|
else:
|
||||||
|
path_str = line
|
||||||
|
params = ""
|
||||||
|
else:
|
||||||
|
# Unquoted path, split on first space
|
||||||
|
parts = line.split(None, 1)
|
||||||
|
path_str = parts[0]
|
||||||
|
params = parts[1] if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
batch_items.append((path_str, params))
|
||||||
|
|
||||||
|
return batch_items
|
||||||
|
|
||||||
|
|
||||||
|
def merge_batch_args(base_args, batch_params_str: str) -> argparse.Namespace:
|
||||||
|
"""
|
||||||
|
Merge batch file row parameters with base CLI parameters.
|
||||||
|
Row parameters override base parameters for that specific path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_args: Base argparse.Namespace from CLI
|
||||||
|
batch_params_str: Parameter string from batch file row
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New argparse.Namespace with merged parameters
|
||||||
|
"""
|
||||||
|
# Create a copy of base args
|
||||||
|
merged = argparse.Namespace(**vars(base_args))
|
||||||
|
|
||||||
|
if not batch_params_str:
|
||||||
|
return merged
|
||||||
|
|
||||||
|
# Parse row parameters as if they were CLI arguments
|
||||||
|
try:
|
||||||
|
param_list = shlex.split(batch_params_str)
|
||||||
|
except ValueError:
|
||||||
|
# If shlex fails, try simple split
|
||||||
|
param_list = batch_params_str.split()
|
||||||
|
|
||||||
|
# Build a parser just for these arguments (reuse the same one)
|
||||||
|
# We'll manually apply known arguments
|
||||||
|
i = 0
|
||||||
|
while i < len(param_list):
|
||||||
|
arg = param_list[i]
|
||||||
|
|
||||||
|
if arg == "--cq":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.cq = int(param_list[i + 1])
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg in ["--m", "--mode"]:
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.transcode_mode = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--encoder":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.encoder = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg in ["--r", "--resolution"]:
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.resolution = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--test":
|
||||||
|
merged.test_mode = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--language":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.audio_language = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--filter-audio":
|
||||||
|
merged.filter_audio = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--audio-select":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.audio_select = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--audio-titles":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.audio_titles = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--audio-channels":
|
||||||
|
if i + 1 < len(param_list):
|
||||||
|
merged.audio_channels = param_list[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif arg == "--keep-all-titles":
|
||||||
|
merged.strip_all_titles = False
|
||||||
|
i += 1
|
||||||
|
elif arg == "--strip-all-titles":
|
||||||
|
merged.strip_all_titles = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--unforce-subs":
|
||||||
|
merged.unforce_subs = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--no-encode":
|
||||||
|
merged.no_encode = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--force-process":
|
||||||
|
merged.force_process = True
|
||||||
|
i += 1
|
||||||
|
elif arg == "--replace":
|
||||||
|
merged.replace_file = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return merged
|
||||||
|
|
||||||
|
|
||||||
|
def parse_audio_dict(audio_str: str, dict_type: str) -> dict:
|
||||||
|
"""
|
||||||
|
Parse audio titles or channels string into dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
audio_str: String like "0:English,1:Commentary" or "0:2,1:6"
|
||||||
|
dict_type: "titles" or "channels"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary mapping stream indices to values, or empty dict on error
|
||||||
|
"""
|
||||||
|
if not audio_str:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
try:
|
||||||
|
pairs = audio_str.split(",")
|
||||||
|
for pair in pairs:
|
||||||
|
stream_idx, value = pair.split(":")
|
||||||
|
stream_idx = int(stream_idx.strip())
|
||||||
|
|
||||||
|
if dict_type == "channels":
|
||||||
|
# Validate channels: only 2 or 6 allowed
|
||||||
|
channels = int(value.strip())
|
||||||
|
if channels not in (2, 6):
|
||||||
|
logger.warning(f"Invalid channel count: {channels}. Only 2 or 6 allowed. Skipping.")
|
||||||
|
continue
|
||||||
|
result[stream_idx] = channels
|
||||||
|
else: # titles
|
||||||
|
result[stream_idx] = value.strip()
|
||||||
|
except (ValueError, IndexError) as e:
|
||||||
|
logger.warning(f"Error parsing audio {dict_type}: {e}")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
# =============================
|
# =============================
|
||||||
# Setup
|
# Setup
|
||||||
# =============================
|
# =============================
|
||||||
@ -96,7 +311,7 @@ Examples:
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument("folder", help="Input folder containing video files")
|
parser.add_argument("folder", nargs="?", default=None, help="Input folder containing video files (required unless using --paths-file)")
|
||||||
parser.add_argument("--cq", type=int, help="Override default CQ value")
|
parser.add_argument("--cq", type=int, help="Override default CQ value")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--m", "--mode", dest="transcode_mode", default="cq",
|
"--m", "--mode", dest="transcode_mode", default="cq",
|
||||||
@ -129,6 +344,14 @@ Examples:
|
|||||||
"--audio-select", dest="audio_select", default=None,
|
"--audio-select", dest="audio_select", default=None,
|
||||||
help="Pre-select audio streams to keep (comma-separated, e.g., 1,2). Skips interactive prompt"
|
help="Pre-select audio streams to keep (comma-separated, e.g., 1,2). Skips interactive prompt"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--audio-titles", dest="audio_titles", default=None,
|
||||||
|
help="Set custom titles for audio streams (e.g., '0:English,1:Commentary'). Format: stream_index:title,stream_index:title"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--audio-channels", dest="audio_channels", default=None,
|
||||||
|
help="Set channel count for specific audio streams (e.g., '0:2,1:6'). Format: stream_index:channels,stream_index:channels. Only 2 or 6 channels allowed"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--keep-all-titles", dest="strip_all_titles", default=True, action="store_false",
|
"--keep-all-titles", dest="strip_all_titles", default=True, action="store_false",
|
||||||
help="Preserve title metadata on audio tracks (default: titles are stripped)"
|
help="Preserve title metadata on audio tracks (default: titles are stripped)"
|
||||||
@ -153,10 +376,6 @@ Examples:
|
|||||||
"--wait", "-w", dest="wait_seconds", type=int, nargs='?', const=-1, default=None,
|
"--wait", "-w", dest="wait_seconds", type=int, nargs='?', const=-1, default=None,
|
||||||
help="Wait after each file (default: 30s with --no-encode, 0s otherwise). Gives Plex time to detect changes"
|
help="Wait after each file (default: 30s with --no-encode, 0s otherwise). Gives Plex time to detect changes"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--split", dest="split_time", default=None,
|
|
||||||
help="Split video at timestamp (e.g., 00:58:15.250). Creates two separate encodes: part1 and part2"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--travel", dest="travel_mode", default=False, action="store_true",
|
"--travel", dest="travel_mode", default=False, action="store_true",
|
||||||
help="Travel mode: force 720p resolution and CQ+2, requires --output flag"
|
help="Travel mode: force 720p resolution and CQ+2, requires --output flag"
|
||||||
@ -165,34 +384,333 @@ Examples:
|
|||||||
"--output", dest="output_folder", default=None,
|
"--output", dest="output_folder", default=None,
|
||||||
help="Output folder for travel mode (creates subfolder based on input folder name)"
|
help="Output folder for travel mode (creates subfolder based on input folder name)"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--paths-file", dest="paths_file", default=None,
|
||||||
|
help="Batch mode: Read paths from file (.txt or .csv). One path per line with optional per-row parameters"
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Load configuration
|
# Load configuration
|
||||||
config_path = Path(__file__).parent / "config.xml"
|
config_path = Path(__file__).parent / "config.xml"
|
||||||
config = load_config_xml(config_path)
|
config = load_config_xml(config_path)
|
||||||
|
|
||||||
# Normalize input path (handle Linux paths, mixed separators, etc.)
|
# =============================
|
||||||
input_path = normalize_input_path(args.folder, config.get("path_mappings", {}))
|
# BATCH MODE
|
||||||
|
# =============================
|
||||||
|
if args.paths_file:
|
||||||
|
paths_file = Path(args.paths_file)
|
||||||
|
if not paths_file.exists():
|
||||||
|
print(f"❌ Paths file not found: {paths_file}")
|
||||||
|
logger.error(f"Paths file not found: {paths_file}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Track what we've already processed
|
||||||
|
processed_items = set()
|
||||||
|
batch_queue = []
|
||||||
|
completed = 0
|
||||||
|
failed = 0
|
||||||
|
total_attempted = 0
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"BATCH MODE: Processing paths from {paths_file.name}")
|
||||||
|
print(f"ℹ️ File will be rechecked after each item for new additions")
|
||||||
|
print("=" * 80)
|
||||||
|
logger.info(f"BATCH MODE: Starting batch processing from {paths_file}")
|
||||||
|
logger.info("File monitoring enabled - will check for new additions after each item")
|
||||||
|
|
||||||
|
# Initial load
|
||||||
|
batch_items = parse_batch_file(paths_file)
|
||||||
|
if not batch_items:
|
||||||
|
print(f"❌ No valid paths found in {paths_file}")
|
||||||
|
logger.error(f"No valid paths in batch file: {paths_file}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"📋 Found {len(batch_items)} initial path(s)\n")
|
||||||
|
|
||||||
|
# Create item signatures for tracking (path + params combo)
|
||||||
|
for path_str, params_str in batch_items:
|
||||||
|
item_sig = f"{path_str}|{params_str}"
|
||||||
|
if item_sig not in processed_items:
|
||||||
|
batch_queue.append((path_str, params_str))
|
||||||
|
|
||||||
|
batch_num = 1
|
||||||
|
|
||||||
|
# Process batch items with recheck after each
|
||||||
|
while batch_queue:
|
||||||
|
path_str, params_str = batch_queue.pop(0)
|
||||||
|
item_sig = f"{path_str}|{params_str}"
|
||||||
|
total_attempted += 1
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"BATCH [{batch_num}]: {path_str}")
|
||||||
|
if params_str:
|
||||||
|
print(f"Parameters: {params_str}")
|
||||||
|
print("-" * 80)
|
||||||
|
logger.info(f"[BATCH {batch_num}] Processing: {path_str}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Normalize path
|
||||||
|
folder = normalize_input_path(path_str, config.get("path_mappings", {}))
|
||||||
|
|
||||||
|
# Check if folder exists
|
||||||
|
if not folder.exists():
|
||||||
|
print(f"❌ [BATCH {batch_num}] Folder not found: {folder}")
|
||||||
|
logger.error(f"[BATCH {batch_num}] Folder not found: {folder}")
|
||||||
|
processed_items.add(item_sig)
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
# Recheck file for new items
|
||||||
|
print(f"\n🔄 Rechecking {paths_file.name} for new additions...")
|
||||||
|
new_batch_items = parse_batch_file(paths_file)
|
||||||
|
for path, params in new_batch_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items and sig not in [f"{p}|{pr}" for p, pr in batch_queue]:
|
||||||
|
batch_queue.append((path, params))
|
||||||
|
print(f" ✨ New item found: {path}")
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Merge batch parameters with base CLI parameters
|
||||||
|
merged_args = merge_batch_args(args, params_str)
|
||||||
|
|
||||||
|
# Handle travel mode
|
||||||
|
travel_output_folder = None
|
||||||
|
if merged_args.travel_mode:
|
||||||
|
if not merged_args.output_folder:
|
||||||
|
print(f"❌ [BATCH {batch_num}] --travel requires --output folder")
|
||||||
|
logger.error(f"[BATCH {batch_num}] --travel requires --output folder")
|
||||||
|
processed_items.add(item_sig)
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
# Recheck file for new items
|
||||||
|
print(f"\n🔄 Rechecking {paths_file.name} for new additions...")
|
||||||
|
new_batch_items = parse_batch_file(paths_file)
|
||||||
|
for path, params in new_batch_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items and sig not in [f"{p}|{pr}" for p, pr in batch_queue]:
|
||||||
|
batch_queue.append((path, params))
|
||||||
|
print(f" ✨ New item found: {path}")
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
output_base = Path(merged_args.output_folder)
|
||||||
|
input_folder_name = folder.name
|
||||||
|
travel_output_folder = output_base / input_folder_name
|
||||||
|
travel_output_folder.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
merged_args.resolution = "720"
|
||||||
|
default_cq = get_default_cq(folder, config, "720", merged_args.encoder)
|
||||||
|
merged_args.cq = default_cq + 2
|
||||||
|
|
||||||
|
# Validate --replace requires --no-encode
|
||||||
|
if merged_args.replace_file and not merged_args.no_encode:
|
||||||
|
print(f"❌ [BATCH {batch_num}] --replace requires --no-encode")
|
||||||
|
logger.error(f"[BATCH {batch_num}] --replace requires --no-encode")
|
||||||
|
processed_items.add(item_sig)
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
# Recheck file for new items
|
||||||
|
print(f"\n🔄 Rechecking {paths_file.name} for new additions...")
|
||||||
|
new_batch_items = parse_batch_file(paths_file)
|
||||||
|
for path, params in new_batch_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items and sig not in [f"{p}|{pr}" for p, pr in batch_queue]:
|
||||||
|
batch_queue.append((path, params))
|
||||||
|
print(f" ✨ New item found: {path}")
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Set wait time
|
||||||
|
if merged_args.wait_seconds is None:
|
||||||
|
merged_args.wait_seconds = 0
|
||||||
|
elif merged_args.wait_seconds == -1:
|
||||||
|
merged_args.wait_seconds = 30 if merged_args.no_encode else 0
|
||||||
|
|
||||||
|
# Parse audio dicts from merged args
|
||||||
|
audio_titles_dict = parse_audio_dict(merged_args.audio_titles, "titles") if merged_args.audio_titles else {}
|
||||||
|
audio_channels_dict = parse_audio_dict(merged_args.audio_channels, "channels") if merged_args.audio_channels else {}
|
||||||
|
|
||||||
|
# Process folder
|
||||||
|
process_folder(
|
||||||
|
folder, merged_args.cq, merged_args.transcode_mode, merged_args.resolution,
|
||||||
|
config, TRACKER_FILE, merged_args.test_mode, merged_args.audio_language,
|
||||||
|
merged_args.filter_audio, merged_args.audio_select, merged_args.encoder,
|
||||||
|
merged_args.strip_all_titles, travel_output_folder, merged_args.unforce_subs,
|
||||||
|
merged_args.no_encode, merged_args.force_process, merged_args.replace_file,
|
||||||
|
merged_args.wait_seconds, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✓ [BATCH {batch_num}] Completed: {folder.name}")
|
||||||
|
logger.info(f"[BATCH {batch_num}] Completed successfully")
|
||||||
|
processed_items.add(item_sig)
|
||||||
|
completed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
# Recheck file for new items after successful completion
|
||||||
|
print(f"\n🔄 Rechecking {paths_file.name} for new additions...")
|
||||||
|
new_batch_items = parse_batch_file(paths_file)
|
||||||
|
new_count = 0
|
||||||
|
for path, params in new_batch_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items and sig not in [f"{p}|{pr}" for p, pr in batch_queue]:
|
||||||
|
batch_queue.append((path, params))
|
||||||
|
print(f" ✨ New item found: {path}")
|
||||||
|
new_count += 1
|
||||||
|
|
||||||
|
if new_count == 0:
|
||||||
|
print(f" (no new additions)")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ [BATCH {batch_num}] Error: {e}")
|
||||||
|
logger.error(f"[BATCH {batch_num}] Error: {e}", exc_info=True)
|
||||||
|
processed_items.add(item_sig)
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
# Recheck file for new items even on error
|
||||||
|
print(f"\n🔄 Rechecking {paths_file.name} for new additions...")
|
||||||
|
try:
|
||||||
|
new_batch_items = parse_batch_file(paths_file)
|
||||||
|
new_count = 0
|
||||||
|
for path, params in new_batch_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items and sig not in [f"{p}|{pr}" for p, pr in batch_queue]:
|
||||||
|
batch_queue.append((path, params))
|
||||||
|
print(f" ✨ New item found: {path}")
|
||||||
|
new_count += 1
|
||||||
|
|
||||||
|
if new_count == 0:
|
||||||
|
print(f" (no new additions)")
|
||||||
|
except Exception as recheck_error:
|
||||||
|
print(f"⚠️ Error rechecking file: {recheck_error}")
|
||||||
|
logger.warning(f"Error during file recheck: {recheck_error}")
|
||||||
|
|
||||||
|
# Final check for any items added while processing the last batch
|
||||||
|
print()
|
||||||
|
print("=" * 80)
|
||||||
|
print("✓ BATCH QUEUE COMPLETE - Performing final file check...")
|
||||||
|
print("=" * 80)
|
||||||
|
final_items = parse_batch_file(paths_file)
|
||||||
|
final_new = []
|
||||||
|
for path, params in final_items:
|
||||||
|
sig = f"{path}|{params}"
|
||||||
|
if sig not in processed_items:
|
||||||
|
final_new.append((path, params))
|
||||||
|
|
||||||
|
if final_new:
|
||||||
|
print(f"📋 Found {len(final_new)} new item(s) added during processing!\n")
|
||||||
|
|
||||||
|
for path_str, params_str in final_new:
|
||||||
|
item_sig = f"{path_str}|{params_str}"
|
||||||
|
total_attempted += 1
|
||||||
|
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"BATCH [{batch_num}]: {path_str}")
|
||||||
|
if params_str:
|
||||||
|
print(f"Parameters: {params_str}")
|
||||||
|
print("-" * 80)
|
||||||
|
logger.info(f"[BATCH {batch_num}] Processing: {path_str}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
folder = normalize_input_path(path_str, config.get("path_mappings", {}))
|
||||||
|
|
||||||
|
if not folder.exists():
|
||||||
|
print(f"❌ [BATCH {batch_num}] Folder not found: {folder}")
|
||||||
|
logger.error(f"[BATCH {batch_num}] Folder not found: {folder}")
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
merged_args = merge_batch_args(args, params_str)
|
||||||
|
|
||||||
|
travel_output_folder = None
|
||||||
|
if merged_args.travel_mode:
|
||||||
|
if not merged_args.output_folder:
|
||||||
|
print(f"❌ [BATCH {batch_num}] --travel requires --output folder")
|
||||||
|
logger.error(f"[BATCH {batch_num}] --travel requires --output folder")
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
output_base = Path(merged_args.output_folder)
|
||||||
|
input_folder_name = folder.name
|
||||||
|
travel_output_folder = output_base / input_folder_name
|
||||||
|
travel_output_folder.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
merged_args.resolution = "720"
|
||||||
|
default_cq = get_default_cq(folder, config, "720", merged_args.encoder)
|
||||||
|
merged_args.cq = default_cq + 2
|
||||||
|
|
||||||
|
if merged_args.replace_file and not merged_args.no_encode:
|
||||||
|
print(f"❌ [BATCH {batch_num}] --replace requires --no-encode")
|
||||||
|
logger.error(f"[BATCH {batch_num}] --replace requires --no-encode")
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if merged_args.wait_seconds is None:
|
||||||
|
merged_args.wait_seconds = 0
|
||||||
|
elif merged_args.wait_seconds == -1:
|
||||||
|
merged_args.wait_seconds = 30 if merged_args.no_encode else 0
|
||||||
|
|
||||||
|
# Parse audio dicts from merged args
|
||||||
|
audio_titles_dict = parse_audio_dict(merged_args.audio_titles, "titles") if merged_args.audio_titles else {}
|
||||||
|
audio_channels_dict = parse_audio_dict(merged_args.audio_channels, "channels") if merged_args.audio_channels else {}
|
||||||
|
|
||||||
|
process_folder(
|
||||||
|
folder, merged_args.cq, merged_args.transcode_mode, merged_args.resolution,
|
||||||
|
config, TRACKER_FILE, merged_args.test_mode, merged_args.audio_language,
|
||||||
|
merged_args.filter_audio, merged_args.audio_select, merged_args.encoder,
|
||||||
|
merged_args.strip_all_titles, travel_output_folder, merged_args.unforce_subs,
|
||||||
|
merged_args.no_encode, merged_args.force_process, merged_args.replace_file,
|
||||||
|
merged_args.wait_seconds, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✓ [BATCH {batch_num}] Completed: {folder.name}")
|
||||||
|
logger.info(f"[BATCH {batch_num}] Completed successfully")
|
||||||
|
completed += 1
|
||||||
|
batch_num += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ [BATCH {batch_num}] Error: {e}")
|
||||||
|
logger.error(f"[BATCH {batch_num}] Error: {e}", exc_info=True)
|
||||||
|
failed += 1
|
||||||
|
batch_num += 1
|
||||||
|
else:
|
||||||
|
print("(no new items found)")
|
||||||
|
|
||||||
|
# Final summary
|
||||||
|
print()
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"✓ BATCH PROCESSING COMPLETE")
|
||||||
|
print(f" Total items processed: {total_attempted}")
|
||||||
|
print(f" ✓ Succeeded: {completed}")
|
||||||
|
if failed > 0:
|
||||||
|
print(f" ❌ Failed: {failed}")
|
||||||
|
print("=" * 80)
|
||||||
|
logger.info(f"Batch processing finished: {completed} succeeded, {failed} failed out of {total_attempted}")
|
||||||
|
|
||||||
# Verify path exists and determine if it's a file or folder
|
|
||||||
if not input_path.exists():
|
|
||||||
print(f"❌ Path not found: {input_path}")
|
|
||||||
logger.error(f"Path not found: {input_path}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Handle file vs folder input
|
# =============================
|
||||||
target_file = None
|
# SINGLE MODE
|
||||||
if input_path.is_file():
|
# =============================
|
||||||
# Single file target
|
if not args.folder:
|
||||||
target_file = input_path
|
parser.print_help()
|
||||||
folder = input_path.parent
|
return
|
||||||
print(f"📄 Target file: {target_file.name}")
|
|
||||||
logger.info(f"Processing single file: {target_file.name}")
|
# Normalize input path (handle Linux paths, mixed separators, etc.)
|
||||||
else:
|
folder = normalize_input_path(args.folder, config.get("path_mappings", {}))
|
||||||
# Folder target (process all files)
|
|
||||||
folder = input_path
|
# Verify folder exists
|
||||||
print(f"📁 Target folder: {folder}")
|
if not folder.exists():
|
||||||
logger.info(f"Processing folder: {folder}")
|
print(f"❌ Folder not found: {folder}")
|
||||||
|
logger.error(f"Folder not found: {folder}")
|
||||||
|
return
|
||||||
|
|
||||||
# Handle travel mode
|
# Handle travel mode
|
||||||
travel_output_folder = None
|
travel_output_folder = None
|
||||||
@ -227,6 +745,45 @@ Examples:
|
|||||||
logger.error("--replace flag used without --no-encode")
|
logger.error("--replace flag used without --no-encode")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Parse audio titles from CLI argument
|
||||||
|
audio_titles_dict = {}
|
||||||
|
if args.audio_titles:
|
||||||
|
try:
|
||||||
|
# Format: "0:English,1:Commentary,2:Descriptive Audio"
|
||||||
|
pairs = args.audio_titles.split(",")
|
||||||
|
for pair in pairs:
|
||||||
|
stream_idx, title = pair.split(":")
|
||||||
|
audio_titles_dict[int(stream_idx.strip())] = title.strip()
|
||||||
|
logger.info(f"Audio titles: {audio_titles_dict}")
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
print("❌ Invalid --audio-titles format. Use: '0:English,1:Commentary'")
|
||||||
|
logger.error(f"Invalid audio titles format: {args.audio_titles}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Parse audio channels from CLI argument
|
||||||
|
audio_channels_dict = {}
|
||||||
|
if args.audio_channels:
|
||||||
|
try:
|
||||||
|
# Format: "0:2,1:6" (stream_index:channel_count)
|
||||||
|
pairs = args.audio_channels.split(",")
|
||||||
|
for pair in pairs:
|
||||||
|
stream_idx, channels = pair.split(":")
|
||||||
|
stream_idx = int(stream_idx.strip())
|
||||||
|
channels = int(channels.strip())
|
||||||
|
|
||||||
|
# Validate that only 2 or 6 channels are allowed
|
||||||
|
if channels not in (2, 6):
|
||||||
|
print(f"❌ Invalid channel count: {channels}. Only 2 or 6 channels allowed")
|
||||||
|
logger.error(f"Invalid channel count: {channels}. Only 2 or 6 channels allowed")
|
||||||
|
return
|
||||||
|
|
||||||
|
audio_channels_dict[stream_idx] = channels
|
||||||
|
logger.info(f"Audio channels: {audio_channels_dict}")
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
print("❌ Invalid --audio-channels format. Use: '0:2,1:6'")
|
||||||
|
logger.error(f"Invalid audio channels format: {args.audio_channels}")
|
||||||
|
return
|
||||||
|
|
||||||
# Set wait time default: 30s if --no-encode and --wait used, 0 otherwise
|
# Set wait time default: 30s if --no-encode and --wait used, 0 otherwise
|
||||||
# -1 means --wait was used without a value (use intelligent default)
|
# -1 means --wait was used without a value (use intelligent default)
|
||||||
if args.wait_seconds is None:
|
if args.wait_seconds is None:
|
||||||
@ -234,8 +791,8 @@ Examples:
|
|||||||
elif args.wait_seconds == -1:
|
elif args.wait_seconds == -1:
|
||||||
args.wait_seconds = 30 if args.no_encode else 0 # --wait used without value
|
args.wait_seconds = 30 if args.no_encode else 0 # --wait used without value
|
||||||
|
|
||||||
# Process folder or single file
|
# Process folder
|
||||||
process_folder(folder, args.cq, args.transcode_mode, args.resolution, config, TRACKER_FILE, args.test_mode, args.audio_language, args.filter_audio, args.audio_select, args.encoder, args.strip_all_titles, travel_output_folder, args.unforce_subs, args.no_encode, args.force_process, args.replace_file, args.wait_seconds, args.split_time, target_file)
|
process_folder(folder, args.cq, args.transcode_mode, args.resolution, config, TRACKER_FILE, args.test_mode, args.audio_language, args.filter_audio, args.audio_select, args.encoder, args.strip_all_titles, travel_output_folder, args.unforce_subs, args.no_encode, args.force_process, args.replace_file, args.wait_seconds, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
26
paths.txt
26
paths.txt
@ -1,7 +1,19 @@
|
|||||||
"P:\movies\Nobody 2 (2025)" --strip-all-titles
|
# Batch Encoding Paths - Simple List Format
|
||||||
"P:\movies\The French Dispatch (2021)" --strip-all-titles
|
# Each line: path [optional parameters]
|
||||||
"P:\movies\Let's Be Cops (2014)" --strip-all-titles
|
# Example formats:
|
||||||
"P:\movies\The Secret World of Arrietty (2010)" --strip-all-titles
|
# P:\movies\Movie1
|
||||||
"P:\movies\Akira (1988)" --strip-all-titles
|
# P:\movies\Movie2 --r 720
|
||||||
"P:\movies\Space Sweepers (2021)" --strip-all-titles
|
# P:\movies\Movie3 --r 720 --cq 28 --encoder av1
|
||||||
"P:\movies\John Carter (2012)" --strip-all-titles
|
|
||||||
|
"P:\movies\Mad Max - Fury Road - Black & Chrome Edition (2015)" --filter-audio
|
||||||
|
"P:\tv\Adventuring Academy" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Dimension 20's Adventuring Party" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Dimension 20" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Crowd Control" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Game Changer" --title-suffix "WebRip-1080p"
|
||||||
|
"P:\tv\Make Some Noise" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Parlor Room" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Smartypants" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Um, Actually" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\tv\Very Important People" --title-suffix " WebRip-1080p"
|
||||||
|
"P:\movies\GOAT (2026)" --r 720
|
||||||
8
paths_batch_example.csv
Normal file
8
paths_batch_example.csv
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
path,resolution,cq,encoder,notes
|
||||||
|
"P:\movies\Nobody 2 (2025)","--r 1080","--cq 32","--encoder hevc","4K downscale"
|
||||||
|
"P:\movies\The French Dispatch (2021)","--r 720","--cq 28","--encoder av1","Low quality source"
|
||||||
|
"P:\movies\Let's Be Cops (2014)","--r 720","","--encoder av1","720p original"
|
||||||
|
"P:\movies\The Secret World of Arrietty (2010)","","--cq 26","","Auto resolution, best quality"
|
||||||
|
"P:\movies\Akira (1988)","--r 1080","--cq 28","--encoder hevc","Anime archive format"
|
||||||
|
"P:\movies\Space Sweepers (2021)","--r 1080","","","Use defaults for this one"
|
||||||
|
"P:\movies\John Carter (2012)","--r 720","--cq 30","--encoder av1","Reduced file size priority"
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
@echo off
|
|
||||||
REM ====================================================================
|
|
||||||
REM Batch Transcode Queue Runner
|
|
||||||
REM Reads paths.txt and processes each line as a separate encode job
|
|
||||||
REM Each line should be a Python command with arguments, e.g.:
|
|
||||||
REM --r 720 --m bitrate "C:\Videos\TV Show"
|
|
||||||
REM --r 1080 --cq 28 "C:\Videos\Movies"
|
|
||||||
REM ====================================================================
|
|
||||||
|
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ====================================================================
|
|
||||||
echo Starting Batch Transcode Queue
|
|
||||||
echo ====================================================================
|
|
||||||
echo.
|
|
||||||
|
|
||||||
set "JOB_COUNT=0"
|
|
||||||
set "SUCCESS_COUNT=0"
|
|
||||||
set "FAILED_COUNT=0"
|
|
||||||
|
|
||||||
for /f "usebackq delims=" %%i in ("paths.txt") do (
|
|
||||||
set /a JOB_COUNT+=1
|
|
||||||
echo.
|
|
||||||
echo [Job !JOB_COUNT!] Processing: %%i
|
|
||||||
echo ======================================
|
|
||||||
|
|
||||||
py main.py %%i
|
|
||||||
|
|
||||||
if errorlevel 1 (
|
|
||||||
set /a FAILED_COUNT+=1
|
|
||||||
echo [Job !JOB_COUNT!] FAILED - Continuing to next item...
|
|
||||||
) else (
|
|
||||||
set /a SUCCESS_COUNT+=1
|
|
||||||
echo [Job !JOB_COUNT!] SUCCESS
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ====================================================================
|
|
||||||
echo Batch Transcode Queue Complete
|
|
||||||
echo ====================================================================
|
|
||||||
echo Total Jobs: !JOB_COUNT!
|
|
||||||
echo Successful: !SUCCESS_COUNT!
|
|
||||||
echo Failed: !FAILED_COUNT!
|
|
||||||
echo ====================================================================
|
|
||||||
pause
|
|
||||||
Loading…
x
Reference in New Issue
Block a user