Updated lt-convert.sh

Amended correct file
This commit is contained in:
Jake P 2025-12-14 03:07:21 +00:00
parent fa6ff5aba1
commit 18d3658d55

View File

@ -1,43 +1,57 @@
#!/bin/bash #!/bin/bash
# =================================================================== # ===================================================================
# LT Converter v3.0 — Professional Edition (December 2025) # GIT Converter v2.7 — Professional Edition (December 2025)
# Author: LeakTechnologies # Author: LeakTechnologies
# Fixed: Converted folder always created in script directory # Modular Architecture for optimal performance
# Fixed: Filter chaining, input validation, bitrate handling
# =================================================================== # ===================================================================
# Force window size in Git Bash on Windows # Force window size and font in Git Bash on Windows
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
printf '\e[8;45;100t' printf '\e[8;100;80t' # Window size 1000x800
printf '\e[14]' # Font size 14
fi fi
# Get the directory where the script is located # Get directory where the script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Always create Converted folder in the script's directory # Always create Converted folder in the script's directory
OUT="$SCRIPT_DIR/Converted" OUT="$SCRIPT_DIR/Converted"
mkdir -p "$OUT" mkdir -p "$OUT"
# Detect optimal encoder at startup # Source modules
optimal_encoder=$(detect_hardware) source "$(dirname "$0")/modules/hardware.sh"
source "$(dirname "$0")/modules/codec.sh"
source "$(dirname "$0")/modules/quality.sh"
source "$(dirname "$0")/modules/filters.sh"
source "$(dirname "$0")/modules/encode.sh"
# Hardware detection and encoder selection # Auto-detect encoder function
detect_hardware() { auto_detect_encoder() {
echo "Detecting hardware and optimal encoder..." echo "Detecting hardware and optimal encoder..." >&2
# Detect GPU type # Detect GPU type
gpu_type="none" gpu_type="none"
# Try NVIDIA detection
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
gpu_type="nvidia" gpu_type="nvidia"
echo " ✓ NVIDIA GPU detected" echo " ✓ NVIDIA GPU detected" >&2
elif lspci 2>/dev/null | grep -iq "amd\|radeon"; then # Try AMD detection with multiple methods
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "amd\|radeon\|advanced micro devices"; then
gpu_type="amd" gpu_type="amd"
echo " ✓ AMD GPU detected" echo " ✓ AMD GPU detected (via lspci)" >&2
elif lspci 2>/dev/null | grep -iq "intel.*vga\|intel.*display"; then elif command -v wmic >/dev/null 2>&1 && wmic path win32_VideoController get name 2>/dev/null | grep -iq "amd\|radeon"; then
gpu_type="amd"
echo " ✓ AMD GPU detected (via wmic)" >&2
# Try Intel detection
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "intel.*vga\|intel.*display"; then
gpu_type="intel" gpu_type="intel"
echo " ✓ Intel GPU detected" echo " ✓ Intel GPU detected (via lspci)" >&2
elif command -v wmic >/dev/null 2>&1 && wmic path win32_VideoController get name 2>/dev/null | grep -iq "intel"; then
gpu_type="intel"
echo " ✓ Intel GPU detected (via wmic)" >&2
else else
echo " ⚠ No GPU detected, will use CPU encoding" echo " ⚠ No GPU detected, will use CPU encoding" >&2
fi fi
# Test encoder availability and speed # Test encoder availability and speed
@ -56,41 +70,44 @@ detect_hardware() {
# Quick benchmark each encoder # Quick benchmark each encoder
for enc in "${candidates[@]}"; do for enc in "${candidates[@]}"; do
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$enc"; then if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$enc"; then
echo " Testing $enc..." echo " Testing $enc..." >&2
start_time=$(date +%s.%N) start_time=$(date +%s)
if ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=2:size=320x240:rate=1" \ if timeout 10 ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=1:size=320x240:rate=1" \
-c:v "$enc" -f null - >/dev/null 2>&1; then -c:v "$enc" -f null - >/dev/null 2>&1; then
end_time=$(date +%s.%N) end_time=$(date +%s)
test_time=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "1") test_time=$((end_time - start_time))
echo " $enc: ${test_time}s" echo " $enc: ${test_time}s (SUCCESS)" >&2
if (( $(echo "$test_time < $best_time" | bc -l 2>/dev/null || echo "0") )); then if [[ $test_time -lt $best_time ]]; then
best_time=$test_time best_time=$test_time
best_encoder=$enc best_encoder=$enc
fi fi
else
echo " $enc: FAILED" >&2
fi fi
else
echo " $enc: NOT AVAILABLE" >&2
fi fi
done done
if [[ -n "$best_encoder" ]]; then if [[ -n "$best_encoder" ]]; then
echo " ✓ Selected: $best_encoder (fastest encoder)" echo " ✓ Selected: $best_encoder (fastest encoder)" >&2
echo "$best_encoder" echo "$best_encoder"
return 0
else else
echo " ⚠ No working encoder found, defaulting to libx265" echo " ⚠ No working encoder found, defaulting to libx265" >&2
echo "libx265" echo "libx265"
return 0
fi fi
} }
# Display header
clear clear
cat << "EOF" cat << "EOF"
╔═══════════════════════════════════════════════════════════════════════════════╗ ╔═══════════════════════════════════════════════════════════════════════════════╗
║ ║ ║ ║
LT Converter v3.0 (December 2025) GIT Converter v2.7 (December 2025)
║ by LeakTechnologies ║ ║ by LeakTechnologies ║
║ ║ ║ ║
║ High-quality batch conversion with hardware acceleration ║ High-quality batch conversion with hardware acceleration ║
║ • AV1 & H.265 support ║ ║ • AV1 & H.265 support ║
║ • Smart upscaling (Source / 720p / 1080p / 1440p / 4K / 2X / 4X) ║ • Smart upscaling (Source / 720p / 1080p / 1440p / 4K / 2X / 4X)
║ • Optional 60 fps smooth motion ║ ║ • Optional 60 fps smooth motion ║
@ -103,205 +120,110 @@ cat << "EOF"
EOF EOF
# — Resolution — # Auto-detect encoder first
echo " Choose your resolution:" echo -e "\n🔍 Auto-detecting optimal encoder..."
optimal_encoder=$(auto_detect_encoder)
echo "✅ Selected: $optimal_encoder"
echo echo
echo " 1) Source file resolution (no upscale)" echo "Press space to continue..."
echo " 2) 720p (1280×720)" read -n 1 -s
echo " 3) 1080p (1920×1080)"
echo " 4) 1440p (2560×1440)" # Get user settings
echo " 5) 4K (3840×2160)" echo
echo " 6) 2X Upscale" echo "╔═══════════════════════════════════════════════════════════════╗"
echo " 7) 4X Upscale" echo "║ Choose Encoder/GPU ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo
echo " 1) Keep auto-detected: $optimal_encoder"
echo " 2) NVIDIA HEVC NVENC"
echo " 3) NVIDIA AV1 NVENC"
echo " 4) AMD HEVC AMF"
echo " 5) AMD AV1 AMF"
echo " 6) Intel HEVC Quick Sync"
echo " 7) Intel AV1 Quick Sync"
echo " 8) CPU SVT-AV1"
echo " 9) CPU x265 HEVC"
echo " 10) Custom encoder selection"
echo echo
while true; do while true; do
read -p " Enter 17 → " res read -p " Enter 110 → " enc_choice
if [[ -n "$res" && "$res" =~ ^[1-7]$ ]]; then if [[ -n "$enc_choice" && "$enc_choice" =~ ^([1-9]|10)$ ]]; then
break break
else else
echo " Invalid input. Please enter a number between 1 and 7." echo " Invalid input. Please enter a number between 1 and 10."
fi fi
done done
case $res in case $enc_choice in
1) scale="" ; res_name="Source" ;; 1)
2) scale="1280:720" ; res_name="720p" ;; echo "✅ Keeping: $optimal_encoder"
3) scale="1920:1080" ; res_name="1080p" ;; ;;
4) scale="2560:1440" ; res_name="1440p" ;; 2)
5) scale="3840:2160" ; res_name="4K" ;; optimal_encoder="hevc_nvenc"
6) scale="iw*2:ih*2" ; res_name="2X" ;; echo "✅ Selected: NVIDIA HEVC NVENC"
7) scale="iw*4:ih*4" ; res_name="4X" ;; ;;
3)
optimal_encoder="av1_nvenc"
echo "✅ Selected: NVIDIA AV1 NVENC"
;;
4)
optimal_encoder="hevc_amf"
echo "✅ Selected: AMD HEVC AMF"
;;
5)
optimal_encoder="av1_amf"
echo "✅ Selected: AMD AV1 AMF"
;;
6)
optimal_encoder="hevc_qsv"
echo "✅ Selected: Intel HEVC Quick Sync"
;;
7)
optimal_encoder="av1_qsv"
echo "✅ Selected: Intel AV1 Quick Sync"
;;
8)
optimal_encoder="libsvtav1"
echo "✅ Selected: CPU SVT-AV1"
;;
9)
optimal_encoder="libx265"
echo "✅ Selected: CPU x265 HEVC"
;;
10)
echo -e "\n⚙ Available Encoders:"
ffmpeg -hide_banner -encoders | grep -E "(hevc|av1|h265)" | grep -v "V\|D" | awk '{print $2}' | nl
while true; do
read -p "Enter encoder name: " custom_enc
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$custom_enc"; then
optimal_encoder="$custom_enc"
echo "✅ Selected: $custom_enc"
break
else
echo "❌ Encoder '$custom_enc' not found. Please try again."
fi
done
;;
esac esac
# — Scaling Algorithm (only if upscaling) — setup_codec_and_container
if [[ -n "$scale" ]]; then get_resolution_settings
clear get_fps_settings
cat << "EOF" get_quality_settings "$optimal_encoder"
╔═══════════════════════════════════════════════════════════════╗ get_color_correction
║ Choose Scaling Algorithm ║
╚═══════════════════════════════════════════════════════════════╝
1) Bicubic (fast, good quality) # Build filter chain
2) Lanczos (best quality, slower) build_filter_chain
3) Bilinear (fastest, basic quality)
EOF
echo
while true; do # Set container from user selection
read -p " Enter 13 → " scale_opt ext="$OUTPUT_CONTAINER"
if [[ -n "$scale_opt" && "$scale_opt" =~ ^[1-3]$ ]]; then
break
else
echo " Invalid input. Please enter a number between 1 and 3."
fi
done
case $scale_opt in # Display encoding summary
1) scale_flags="bicubic" ;;
2) scale_flags="lanczos" ;;
3) scale_flags="bilinear" ;;
esac
else
scale_flags="lanczos" # Default for consistency
fi
# — Encoding Options —
clear
cat << "EOF"
╔═════════════════════════════════════════════════════════════╗
║ Encoding Options ║
╚═══════════════════════════════════════════════════════════════╝
Auto-detected encoder: $optimal_encoder
1) Original FPS
2) 60 FPS
EOF
echo echo
echo "Encoding → $ENCODER | $res_name | $ext $suf${color_suf} @ $quality_name"
while true; do
read -p " Enter 12 → " c
if [[ -n "$c" && "$c" =~ ^[1-2]$ ]]; then
break
else
echo " Invalid input. Please enter 1 or 2."
fi
done
# Set container and FPS
ext="mkv"
fps_filter=""
suf=""
if [[ "$c" == "2" ]]; then
fps_filter="fps=60"
suf="_60fps"
fi
# Use auto-detected encoder
codec="$optimal_encoder"
# — Color Correction Option —
clear
cat << "EOF"
╔═══════════════════════════════════════════════════════════════╗
║ Color Correction Option ║
╚═══════════════════════════════════════════════════════════════╝
1) No color correction
2) Restore pink skin tones (Topaz AI fix)
3) Warm color boost
4) Cool color boost
5) 2000s DVD Restore
6) 90s Quality Restore
7) VHS Quality Restore
8) Anime Preservation (clean lines & colors)
EOF
echo
while true; do
read -p " Enter 18 → " color_opt
if [[ -n "$color_opt" && "$color_opt" =~ ^[1-8]$ ]]; then
break
else
echo " Invalid input. Please enter a number between 1 and 8."
fi
done
case $color_opt in
1) color_filter=""; color_suf="" ;;
2) color_filter="eq=contrast=1.05:brightness=0.02:saturation=1.1:hue=-0.02"; color_suf="_colorfix" ;;
3) color_filter="eq=contrast=1.03:brightness=0.01:saturation=1.15:hue=-0.01"; color_suf="_warm" ;;
4) color_filter="eq=contrast=1.03:brightness=0.01:saturation=0.95:hue=0.02"; color_suf="_cool" ;;
5) color_filter="eq=contrast=1.08:brightness=0.03:saturation=1.2:hue=0:gamma=0.95,unsharp=4:4:0.8:4:4:0.0"; color_suf="_dvdrestore" ;;
6) color_filter="eq=contrast=1.12:brightness=0.05:saturation=1.3:hue=0:gamma=0.92,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_90srestore" ;;
7) color_filter="eq=contrast=1.15:brightness=0.08:saturation=1.4:hue=0:gamma=0.90,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_vhsrestore" ;;
8) color_filter="eq=contrast=1.02:brightness=0:saturation=1.05:hue=0:gamma=1.0,unsharp=3:3:0.5:3:3:0.0,gradfun=2.5:2.5"; color_suf="_anime" ;;
esac
# — Quality Selection —
clear
cat << "EOF"
╔═══════════════════════════════════════════════════════════════╗
║ Choose Quality Mode ║
╚═══════════════════════════════════════════════════════════════╝
1) High Quality AV1 (CRF 18) - Best compression
2) High Quality HEVC (CRF 18) - Fast encoding
3) Near-Lossless AV1 (CRF 16) - Maximum quality
4) Near-Lossless HEVC (CRF 16) - Quality/Speed balance
5) Custom bitrate
EOF
echo
while true; do
read -p " Enter 15 → " b
if [[ -n "$b" && "$b" =~ ^[1-5]$ ]]; then
break
else
echo " Invalid input. Please enter a number between 1 and 5."
fi
done
# Set quality parameters based on auto-detected encoder
case $b in
1)
if [[ "$codec" == *"av1"* ]]; then
quality_params="-crf 18 -preset 6"
quality_name="AV1 CRF 18"
else
quality_params="-crf 18 -quality 23"
quality_name="HEVC CRF 18"
fi
;;
2)
if [[ "$codec" == *"av1"* ]]; then
quality_params="-crf 16 -preset 4"
quality_name="AV1 CRF 16"
else
quality_params="-crf 16 -quality 28"
quality_name="HEVC CRF 16"
fi
;;
3)
echo
echo "Enter bitrate (e.g., 5000k, 8000k):"
read -p "→ " custom_bitrate
if [[ -n "$custom_bitrate" ]]; then
quality_params="-b:v $custom_bitrate"
quality_name="Custom $custom_bitrate"
else
quality_params="-crf 18 -quality 23"
quality_name="HEVC CRF 18"
fi
;;
esac
# Force 8-bit input with performance optimization
bitdepth_filter="-pix_fmt yuv420p -movflags +faststart"
echo
echo "Encoding → $codec | $res_name | $ext $suf${color_suf} @ $quality_name"
echo echo
# Process video files - handle drag-and-drop vs double-click # Process video files - handle drag-and-drop vs double-click
@ -323,54 +245,8 @@ else
echo "Processing all video files in current directory: ${#video_files[@]} file(s)" echo "Processing all video files in current directory: ${#video_files[@]} file(s)"
fi fi
for f in "${video_files[@]}"; do # Process all files
[[ -f "$f" ]] || continue process_files "$ENCODER" "$quality_params" "$filter_chain" "$suf" "$color_suf" "$ext" "${video_files[@]}"
# Extract basename for output filename (handles both relative and absolute paths)
basename_f=$(basename "$f")
out="$OUT/${basename_f%.*}${suf}${color_suf}__cv.$ext"
[[ -f "$out" ]] && { echo "SKIP $f (already exists)"; continue; }
# Build filter chain
filter_chain=""
if [[ -n "$scale" ]]; then
filter_chain="scale=${scale}:flags=${scale_flags}"
fi
if [[ -n "$fps_filter" ]]; then
if [[ -n "$filter_chain" ]]; then
filter_chain="${filter_chain},${fps_filter}"
else
filter_chain="$fps_filter"
fi
fi
if [[ -n "$color_filter" ]]; then
if [[ -n "$filter_chain" ]]; then
filter_chain="${filter_chain},${color_filter}"
else
filter_chain="$color_filter"
fi
fi
echo "Processing: $f$(basename "$out")"
# Build optimized ffmpeg command
if [[ -n "$filter_chain" ]]; then
ffmpeg -y -i "$f" -pix_fmt yuv420p -vf "$filter_chain" \
-c:v "$codec" $quality_params -c:a aac -b:a 192k -ac 2 "$out"
else
ffmpeg -y -i "$f" -pix_fmt yuv420p \
-c:v "$codec" $quality_params -c:a aac -b:a 192k -ac 2 "$out"
fi
if [[ $? -eq 0 ]]; then
echo "DONE → $(basename "$out")"
else
echo "ERROR → Failed to process $f"
fi
echo
done
echo "========================================================" echo "========================================================"
echo "All finished — files in '$OUT'" echo "All finished — files in '$OUT'"