Files
shell_auto_mkvmerge/bin/auto_sort.sh

204 lines
8.2 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Auto Sort — sortiert Videodateien nach Audio-/Untertitel-Spuren
# mit Erkennung zu langer Ordnernamen → generische Gruppennamen
set -euo pipefail
# --------------------------------------------------------------------
# CONFIG / COLORS
# --------------------------------------------------------------------
settings_file="./settings.ini"
ffprobe_path="/usr/bin/ffprobe"
RED='\033[0;31m'
GREEN='\033[0;92m'
BLUE='\033[0;94m'
YELLOW='\033[0;33m'
WHITE_ON_GRAY='\033[0;37;100m'
BLACK_ON_WHITE='\033[0;30;47m'
WHITE_ON_RED='\033[0;37;41m'
YELLOW_ON_WHITE='\033[0;37;43m'
NC='\033[0m'
declare -A group_map # Map von Kombination → Ordnername
declare -A files_by_group # Map von Kombination → Liste von Dateien
declare -a combinations # Liste aller eindeutigen Kombinationen
# --------------------------------------------------------------------
# FUNKTIONEN
# --------------------------------------------------------------------
extract_audio_languages_and_codecs() {
local file=$1
local ffprobe_json
ffprobe_json=$("$ffprobe_path" -v error -show_streams -of json "$file")
local audio_streams=()
while IFS= read -r s; do
codec_name=$(echo "$s" | jq -r '.codec_name')
language=$(echo "$s" | jq -r '.tags.language // "unknown"')
audio_streams+=("[$codec_name"_"$language]")
done < <(echo "$ffprobe_json" | jq -c '.streams[] | select(.codec_type=="audio")')
echo "${audio_streams[@]}"
}
extract_subtitle_languages_and_forced_tags() {
local file=$1
local ffprobe_json
ffprobe_json=$("$ffprobe_path" -v error -show_streams -of json "$file")
local subtitle_streams=()
while IFS= read -r s; do
language=$(echo "$s" | jq -r '.tags.language // "unknown"')
forced_flag=$(echo "$s" | jq -r '.disposition.forced // 0')
if [[ "$forced_flag" == "1" ]]; then
subtitle_streams+=("[forced_$language]")
fi
subtitle_streams+=("[$language]")
done < <(echo "$ffprobe_json" | jq -c '.streams[] | select(.codec_type=="subtitle")')
echo "${subtitle_streams[@]}"
}
relativ_to_fullpath() {
local path="$1"
local scriptpath
scriptpath="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
path=$(echo "$path" | sed 's|/+|/|g')
if [ ! -e "$path" ]; then
realpath "$(dirname "$scriptpath")/$path" 2>/dev/null || echo "$path"
else
realpath "$path" 2>/dev/null || echo "$path"
fi
}
get_user_variables_from_ini_file() {
settings_file=$(relativ_to_fullpath "$settings_file")
if [ ! -e "$settings_file" ]; then
echo -e "${WHITE_ON_RED} Settingsfile nicht gefunden: $settings_file ${NC}"
exit 1
fi
input_folder=$(sed -nr "/^\[pathes\]/ { :l /^input_folder[ ]*=/ { s/[^=]*=[ ]*//; p; q;}; n; b l;}" "$settings_file")
output_folder=$(sed -nr "/^\[pathes\]/ { :l /^output_folder[ ]*=/ { s/[^=]*=[ ]*//; p; q;}; n; b l;}" "$settings_file")
}
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
main() {
get_user_variables_from_ini_file
output_dir="$input_folder/[0] Sort"
output_dir=$(echo "$output_dir" | sed 's|//|/|g')
mkdir -p "$output_dir"
echo "──────────────────────────────────────────────────────────────"
echo -e "${BLACK_ON_WHITE} Auto Sort — Analysephase ${NC}"
echo "──────────────────────────────────────────────────────────────"
# 1⃣ Alle Dateien analysieren und Kombinationen erfassen
found_any=false
# Sortierordner-Pfad in ein sauberes Pattern für find umwandeln
escaped_output_dir=$(printf '%s\n' "$output_dir" | sed 's/[][\.*^$(){}?+|/]/\\&/g')
while IFS= read -r file; do
found_any=true
relative_path=$(realpath --relative-to="$input_folder" "$file")
# Sample-Dateien erkennen (case-insensitive, am Ende des Dateinamens)
basename_lower=$(basename "$file" | tr '[:upper:]' '[:lower:]')
if [[ "$basename_lower" =~ \.sample\.(mkv|mp4|avi|vob|ts|mpeg|mov)$ ]]; then
echo -e "${YELLOW_ON_WHITE} Überspringe Sample ${NC} $relative_path"
echo -e "${YELLOW_ON_WHITE} Grund ${NC} Enthält '.sample' vor Dateiendung${NC}"
continue
fi
audio_streams=$(extract_audio_languages_and_codecs "$file")
subtitle_streams=$(extract_subtitle_languages_and_forced_tags "$file")
if [ -z "$audio_streams" ] && [ -z "$subtitle_streams" ]; then
echo -e "${WHITE_ON_RED} Keine Audio-/Subtitle-Spuren: ${NC} $relative_path"
continue
fi
# Ausgabe der gefundenen Spuren
echo -e "${WHITE_ON_GRAY} Datei ${NC} $relative_path"
if [ -n "$audio_streams" ]; then
echo -e " 🎧 ${GREEN}Audio:${NC} $audio_streams"
else
echo -e " 🎧 ${RED}Audio:${NC} (keine)"
fi
if [ -n "$subtitle_streams" ]; then
echo -e " 💬 ${YELLOW}Subtitles:${NC} $subtitle_streams"
else
echo -e " 💬 ${RED}Subtitles:${NC} (keine)"
fi
combined_streams="$audio_streams | $subtitle_streams"
files_by_group["$combined_streams"]+="$file"$'\n'
done < <(
find "$input_folder" \
-type d -regex "^$escaped_output_dir$" -prune -false -o \
-type d -regex "^$escaped_output_dir/.*" -prune -false -o \
-type f \( \
-iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" -o \
-iname "*.ts" -o -iname "*.vob" -o -iname "*.mpeg" -o -iname "*.mov" \
\) -print
)
if [ "$found_any" = false ]; then
echo "──────────────────────────────────────────────────────────────"
echo -e "${YELLOW_ON_WHITE} Keine neuen Videodateien gefunden. ${NC}"
echo "──────────────────────────────────────────────────────────────"
read -rp "Zum Schließen bitte [ENTER] drücken ..."
exit 0
fi
# 2⃣ Ordnernamen prüfen
group_counter=1
for combo in "${!files_by_group[@]}"; do
folder_name=$(echo "$combo" | tr -s ' ' '_')
target_folder="$output_dir/$folder_name"
if [ ${#target_folder} -gt 240 ]; then
folder_name="Gruppe_${group_counter}"
((group_counter++))
fi
group_map["$combo"]="$folder_name"
combinations+=("$combo")
done
echo "──────────────────────────────────────────────────────────────"
echo -e "${BLACK_ON_WHITE} Verschiebe Dateien ${NC}"
echo "──────────────────────────────────────────────────────────────"
# 3⃣ Dateien verschieben
for combo in "${combinations[@]}"; do
folder_name="${group_map[$combo]}"
target_folder="$output_dir/$folder_name"
mkdir -p "$target_folder"
while IFS= read -r file; do
[ -z "$file" ] && continue
relative_path=$(realpath --relative-to="$input_folder" "$file")
echo -e "${WHITE_ON_GRAY}${NC} ${relative_path}"
echo -e " nach ${GREEN}$folder_name${NC}"
mv "$file" "$target_folder/"
done <<< "${files_by_group[$combo]}"
done
echo "──────────────────────────────────────────────────────────────"
echo -e "${BLACK_ON_WHITE} Fertig! ${NC}"
}
# Main
main
echo
read -rp "Zum Schließen bitte [ENTER] drücken ..."
exit 0
$SHELL