From 12c4b47419c71a7595e948b669e5b1d9ca18a90f Mon Sep 17 00:00:00 2001 From: Kontros Date: Wed, 5 Feb 2025 21:10:39 +0100 Subject: [PATCH] =?UTF-8?q?Erpropte=20relativ=20zuverl=C3=A4ssige=20Versio?= =?UTF-8?q?n=20f=C3=BCr=20Blurays?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert.sh | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100755 convert.sh diff --git a/convert.sh b/convert.sh new file mode 100755 index 0000000..6c9dc36 --- /dev/null +++ b/convert.sh @@ -0,0 +1,211 @@ +#!/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" \ No newline at end of file