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
# ===================================================================
# LT Converter v3.0 — Professional Edition (December 2025)
# GIT Converter v2.7 — Professional Edition (December 2025)
# Author: LeakTechnologies
# Fixed: Converted folder always created in script directory
# Fixed: Filter chaining, input validation, bitrate handling
# Modular Architecture for optimal performance
# ===================================================================
# Force window size in Git Bash on Windows
# Force window size and font in Git Bash on Windows
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
# Get the directory where the script is located
# Get directory where the script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Always create Converted folder in the script's directory
OUT="$SCRIPT_DIR/Converted"
mkdir -p "$OUT"
# Detect optimal encoder at startup
optimal_encoder=$(detect_hardware)
# Source modules
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
detect_hardware() {
echo "Detecting hardware and optimal encoder..."
# Auto-detect encoder function
auto_detect_encoder() {
echo "Detecting hardware and optimal encoder..." >&2
# Detect GPU type
gpu_type="none"
# Try NVIDIA detection
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
gpu_type="nvidia"
echo " ✓ NVIDIA GPU detected"
elif lspci 2>/dev/null | grep -iq "amd\|radeon"; then
echo " ✓ NVIDIA GPU detected" >&2
# 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"
echo " ✓ AMD GPU detected"
elif lspci 2>/dev/null | grep -iq "intel.*vga\|intel.*display"; then
echo " ✓ AMD GPU detected (via lspci)" >&2
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"
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
echo " ⚠ No GPU detected, will use CPU encoding"
echo " ⚠ No GPU detected, will use CPU encoding" >&2
fi
# Test encoder availability and speed
@ -56,41 +70,44 @@ detect_hardware() {
# Quick benchmark each encoder
for enc in "${candidates[@]}"; do
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$enc"; then
echo " Testing $enc..."
start_time=$(date +%s.%N)
if ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=2:size=320x240:rate=1" \
echo " Testing $enc..." >&2
start_time=$(date +%s)
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
end_time=$(date +%s.%N)
test_time=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "1")
echo " $enc: ${test_time}s"
if (( $(echo "$test_time < $best_time" | bc -l 2>/dev/null || echo "0") )); then
end_time=$(date +%s)
test_time=$((end_time - start_time))
echo " $enc: ${test_time}s (SUCCESS)" >&2
if [[ $test_time -lt $best_time ]]; then
best_time=$test_time
best_encoder=$enc
fi
else
echo " $enc: FAILED" >&2
fi
else
echo " $enc: NOT AVAILABLE" >&2
fi
done
if [[ -n "$best_encoder" ]]; then
echo " ✓ Selected: $best_encoder (fastest encoder)"
echo " ✓ Selected: $best_encoder (fastest encoder)" >&2
echo "$best_encoder"
return 0
else
echo " ⚠ No working encoder found, defaulting to libx265"
echo " ⚠ No working encoder found, defaulting to libx265" >&2
echo "libx265"
return 0
fi
}
# Display header
clear
cat << "EOF"
╔═══════════════════════════════════════════════════════════════════════════════╗
║ ║
LT Converter v3.0 (December 2025)
GIT Converter v2.7 (December 2025)
║ by LeakTechnologies ║
║ ║
║ High-quality batch conversion with hardware acceleration
║ High-quality batch conversion with hardware acceleration ║
║ • AV1 & H.265 support ║
║ • Smart upscaling (Source / 720p / 1080p / 1440p / 4K / 2X / 4X)
║ • Optional 60 fps smooth motion ║
@ -103,205 +120,110 @@ cat << "EOF"
EOF
# — Resolution —
echo " Choose your resolution:"
# Auto-detect encoder first
echo -e "\n🔍 Auto-detecting optimal encoder..."
optimal_encoder=$(auto_detect_encoder)
echo "✅ Selected: $optimal_encoder"
echo
echo " 1) Source file resolution (no upscale)"
echo " 2) 720p (1280×720)"
echo " 3) 1080p (1920×1080)"
echo " 4) 1440p (2560×1440)"
echo " 5) 4K (3840×2160)"
echo " 6) 2X Upscale"
echo " 7) 4X Upscale"
echo "Press space to continue..."
read -n 1 -s
# Get user settings
echo
echo "╔═══════════════════════════════════════════════════════════════╗"
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
while true; do
read -p " Enter 17 → " res
if [[ -n "$res" && "$res" =~ ^[1-7]$ ]]; then
read -p " Enter 110 → " enc_choice
if [[ -n "$enc_choice" && "$enc_choice" =~ ^([1-9]|10)$ ]]; then
break
else
echo " Invalid input. Please enter a number between 1 and 7."
echo " Invalid input. Please enter a number between 1 and 10."
fi
done
case $res in
1) scale="" ; res_name="Source" ;;
2) scale="1280:720" ; res_name="720p" ;;
3) scale="1920:1080" ; res_name="1080p" ;;
4) scale="2560:1440" ; res_name="1440p" ;;
5) scale="3840:2160" ; res_name="4K" ;;
6) scale="iw*2:ih*2" ; res_name="2X" ;;
7) scale="iw*4:ih*4" ; res_name="4X" ;;
case $enc_choice in
1)
echo "✅ Keeping: $optimal_encoder"
;;
2)
optimal_encoder="hevc_nvenc"
echo "✅ Selected: NVIDIA HEVC NVENC"
;;
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
# — Scaling Algorithm (only if upscaling) —
if [[ -n "$scale" ]]; then
clear
cat << "EOF"
╔═══════════════════════════════════════════════════════════════╗
║ Choose Scaling Algorithm ║
╚═══════════════════════════════════════════════════════════════╝
setup_codec_and_container
get_resolution_settings
get_fps_settings
get_quality_settings "$optimal_encoder"
get_color_correction
1) Bicubic (fast, good quality)
2) Lanczos (best quality, slower)
3) Bilinear (fastest, basic quality)
EOF
echo
# Build filter chain
build_filter_chain
while true; do
read -p " Enter 13 → " scale_opt
if [[ -n "$scale_opt" && "$scale_opt" =~ ^[1-3]$ ]]; then
break
else
echo " Invalid input. Please enter a number between 1 and 3."
fi
done
# Set container from user selection
ext="$OUTPUT_CONTAINER"
case $scale_opt in
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
# Display encoding summary
echo
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 "Encoding → $ENCODER | $res_name | $ext $suf${color_suf} @ $quality_name"
echo
# 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)"
fi
for f in "${video_files[@]}"; do
[[ -f "$f" ]] || continue
# 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
# Process all files
process_files "$ENCODER" "$quality_params" "$filter_chain" "$suf" "$color_suf" "$ext" "${video_files[@]}"
echo "========================================================"
echo "All finished — files in '$OUT'"