bdrip-mkvconvert/convert.sh

211 lines
7.8 KiB
Bash
Executable File

#!/bin/bash
# Install dependencies:
# sudo dnf install ffmpeg mkvtoolnix jq
# tesseract tesseract-langpack-eng tesseract-langpack-deu
# Konfiguration
INPUT_DIR="$1" # Verzeichnis mit den MKV-Dateien
OUTPUT_DIR="$2" # Verzeichnis für die komprimierten Dateien
RF_VALUE=20 # Qualität (niedriger = bessere Qualität)
AAC_BITRATE_DEFAULT="192k" # Standard-Bitrate für Stereo AAC-Tonspuren
echo "Eingabeverzeichnis: $INPUT_DIR"
echo "Ausgabeverzeichnis: $OUTPUT_DIR"
audio_file=$(mktemp)
map_file=$(mktemp)
crop_file=$(mktemp)
mkdir -p "$OUTPUT_DIR"
# Schleife über alle MKV-Dateien
for file in "$INPUT_DIR"/*.mkv; do
# Dateiname ohne Verzeichnis und Erweiterung
filename=$(basename -- "$file")
name="${filename%.*}"
echo "Verarbeite Datei: $filename"
#JSON-Daten extrahieren
JSON=$(mkvmerge -J "$file")
(
for lang in "ger" "eng"; do
# Spur-IDs extrahieren
SPUR_IDS=$(echo "$JSON" | jq -r \
--arg lang "$lang" \
'.tracks[] | select(.type == "subtitles" and .codec == "HDMV PGS" and .properties.language == $lang) | .id')
TEMP_DIR=$(mktemp -d) # Temporäres Verzeichnis für die Dateigrößenanalyse
declare -A FILE_SIZES # Array für die Zuordnung von Spur-ID zu Dateigröße
# Untertitel extrahieren und Dateigrößen ermitteln
for ID in $SPUR_IDS; do
OUTPUT_FILE="$TEMP_DIR/$lang.$ID.pgs"
echo "Extrahiere Untertitel (Sprache: $lang) - Spur-ID: $ID"
mkvextract tracks "$file" "$ID:$OUTPUT_FILE"
if [[ -f "$OUTPUT_FILE" ]]; then
FILE_SIZE=$(stat -c%s "$OUTPUT_FILE") # Größe der Datei in Bytes
FILE_SIZES["$ID"]=$FILE_SIZE
else
echo "Fehler: Die Datei $OUTPUT_FILE wurde nicht extrahiert!"
fi
done
# Sortiere Spur-IDs nach Dateigröße (aufsteigend)
SORTED_IDS=$(for id in "${!FILE_SIZES[@]}"; do echo "$id ${FILE_SIZES[$id]}"; done | sort -k2 -n | awk '{print $1}')
INDEX=0
for ID in $SORTED_IDS; do
OUTPUT_FILE="$OUTPUT_DIR/${filename%.*}.$lang"
# Benennung basierend auf der Indexposition nach der Sortierung
if [ $INDEX -eq 0 ]; then
# Kleinste Datei → "forced"
OUTPUT_FILE="$OUTPUT_FILE.forced.pgs"
elif [ $INDEX -eq $((${#SORTED_IDS[@]} - 1)) ]; then
# Größte Datei → "hearing_impaired" (optional)
OUTPUT_FILE="$OUTPUT_FILE.hi.pgs"
else
# Übrige Dateien → "regular"
OUTPUT_FILE="$OUTPUT_FILE.pgs"
fi
# Überprüfen, ob die Datei existiert und umbenennen
if [[ -f "$TEMP_DIR/$lang.$ID.pgs" ]]; then
mv "$TEMP_DIR/$lang.$ID.pgs" "$OUTPUT_FILE"
echo "Benenne Spur-ID $ID als $OUTPUT_FILE"
else
echo "Fehler: Die Datei für Spur-ID $ID existiert nicht!"
fi
INDEX=$((INDEX + 1))
done
# Temporäres Verzeichnis entfernen
rm -r "$TEMP_DIR"
done
) &
(
# Audio-Streams verarbeiten
audio_options=""
map_options=""
audio_index=0 # Zählt die AAC-Audiospuren
# Liste für Tonspuren pro Sprache
declare -A audio_tracks
# Ausgabe der gesamten ffmpeg-Informationen über Audio-Streams
echo "Extrahiere Audio-Streams für $filename:"
audio_info=$(ffmpeg -analyzeduration 200000000 -probesize 100000000 -i "$file" 2>&1 | grep "Audio")
# Analysiere die Track-Informationen
while IFS= read -r track_info; do
echo "Track info: $track_info"
index=$(echo "$track_info" | grep -oP '(?<=Stream #0:)\d+')
codec=$(echo "$track_info" | grep -oP '(?<=Audio: )[^ ,]+')
lang=$(echo "$track_info" | awk -F'[()]' '{print $2}')
bitrate=$(echo "$track_info" | grep -oP '\d{3,4} kb/s' | grep -oP '\d+' || echo "0")
channels=$(echo "$track_info" | grep -oP '\d+\.\d+')
channel_layout=$(echo "$track_info" | grep -oP '\d+\.\d+\(.*?\)' | sed 's/^[^(]*//;s/[()]//g')
echo "Index: $index, Codec: $codec, Sprache: $lang, Bitrate: ${bitrate}kbps, Kanäle: $channels, Layout: $channel_layout"
# Nur relevante Sprachen verarbeiten
if [[ "$lang" == "deu" || "$lang" == "eng" ]]; then
# High-Resolution Audio (z.B. DTS-HD MA oder TrueHD)
if [[ "$codec" == "dts" || "$codec" == "truehd" ]]; then
echo "DTS oder TrueHD gefunden, extrahiere Audiospur"
mkvextract "$file" tracks $index:"$OUTPUT_DIR/${name}.${lang}.mka"
# Füge die AAC-Spur für die MKV-Datei hinzu (192kbps Stereo)
audio_options+=" -c:a:$audio_index aac -b:a:$audio_index 192k -ac:a:$audio_index 2 -metadata:s:a:$audio_index language=\"$lang\" -metadata:s:a:$audio_index title=\"Stereo\""
map_options+=" -map 0:$index"
audio_index=$((audio_index + 1))
else
# Speichere alle relevanten Spuren zur späteren Filterung
audio_tracks["$lang"]+="$index:$bitrate:$codec:$channels:$channel_layout "
fi
fi
done <<< "$audio_info"
# Filtere die Spuren mit der höchsten Bitrate pro Sprache
for lang in "${!audio_tracks[@]}"; do
best_track=$(echo "${audio_tracks[$lang]}" | tr ' ' '\n' | sort -t':' -k2 -nr | head -n 1)
best_index=$(echo "$best_track" | cut -d':' -f1)
best_bitrate=$(echo "$best_track" | cut -d':' -f2)
best_codec=$(echo "$best_track" | cut -d':' -f3)
best_channels=$(echo "$best_track" | cut -d':' -f4)
best_layout=$(echo "$best_track" | cut -d':' -f5)
# Fallback-Bitrate auf 192kbps, wenn keine Bitrate ermittelt werden konnte
if [[ "$best_bitrate" == "0" ]]; then
best_bitrate="192"
echo "Keine Bitrate gefunden, Fallback auf 192kbps"
fi
# Kanal-Layout setzen
if [[ "$best_layout" == "side" || "$best_channels" == "6.0" ]]; then
title="Surround 5.1"
best_layout="5.1" # Ersetze "side" durch "5.1"
else
title="Stereo"
best_layout="stereo" # Für alles andere Stereo als Fallback
fi
echo "Verwende beste Spur für $lang: Index $best_index, Bitrate ${best_bitrate}kbps, Codec $best_codec, Kanäle: $best_channels, Layout: $best_layout"
audio_options+=" -c:a:$audio_index aac -b:a:$audio_index ${best_bitrate}k -metadata:s:a:$audio_index language=\"$lang\" -metadata:s:a:$audio_index bitrate=\"$bitrate\" -metadata:s:a:$audio_index title=\"$title\" -channel_layout:a:$audio_index \"$best_layout\""
map_options+=" -map 0:$best_index"
audio_index=$((audio_index + 1))
done
# Ausgabe der finalen Optionen für ffmpeg
echo "Map-Optionen: $map_options"
echo "Audio-Optionen: $audio_options"
# Ergebnisse speichern
echo "$audio_options" > "$audio_file"
echo "$map_options" > "$map_file"
) &
(
echo "Versuche schwarze Balken zu finden und zu entfernen"
crop=$(ffmpeg -i "$file" -vf cropdetect -f null - 2>&1 | grep -oP "crop=\d+:\d+:\d+:\d+" | tail -1)
crop_options=""
# Überprüfen, ob Werte gefunden wurden
if [ -n "$crop" ]; then
echo "Gefundene Crop-Werte: $crop"
# Anwenden der Crop-Werte
crop_options=" -vf \"$crop\""
else
echo "Keine Crop-Werte gefunden!"
fi
echo "$crop_options" > "$crop_file"
) &
wait
# Ergebnisse einlesen
audio_options=$(cat "$audio_file")
map_options=$(cat "$map_file")
crop_options=$(cat "$crop_file")
#debug="-b:v 5M -maxrate 6M -bufsize 10M -g 48 -bf 3"
additional_options="-profile:v main -level 4.1 -preset slow $debug"
ffmpeg_cmd="ffmpeg -loglevel warning -analyzeduration 200000000 -probesize 100000000 -i \"$file\"$crop_options -c:v h264_nvenc -cq $RF_VALUE $additional_options $map_options $audio_options -c:s copy -map 0:v -map_metadata -1 \"$OUTPUT_DIR/${name}.mkv\""
echo "Führe folgenden Befehl aus: $ffmpeg_cmd"
eval $ffmpeg_cmd
echo "Komprimierte Datei erstellt: $OUTPUT_DIR/${name}.mkv"
echo ""
done 2>&1 | tee convert.log
# Temporäre Dateien aufräumen
rm "$audio_file" "$map_file" "$crop_file"