390 lines
13 KiB
Bash
Executable File
390 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
italic="\033[3m"
|
|
#underline="\033[4m"
|
|
#ita_under="\033[3;4m"
|
|
#bgd="\033[1;4;31m"
|
|
red="\033[1;31m"
|
|
green="\033[1;32m"
|
|
yellow="\033[1;33m"
|
|
bold="\033[1m"
|
|
#box="\033[1;41m"
|
|
reset="\033[0m"
|
|
|
|
shopt -s globstar
|
|
|
|
command -v jq >/dev/null 2>&1 || { echo -e "${bold}93mhandbrake_for_plex${reset} require ${bold}jq${reset} but it's not installed.\nRun ${italic}(brew install jq)${reset}\nAborting..." >&2; exit 1; }
|
|
|
|
|
|
showHelp() {
|
|
clear
|
|
echo -e "\033[93mhandbrake_for_plex.sh\033[0m"
|
|
echo "Convert and rename video files for Plex:"
|
|
echo
|
|
echo
|
|
echo "USAGE: handbrake_for_plex.sh"
|
|
echo
|
|
echo "Configure:"
|
|
echo " -\$SRC : source folder (recursive)"
|
|
echo " -\$DEST : destination folder"
|
|
echo " -\$DEST_EXT : destination extension"
|
|
echo " -\$PRESET : preset HandBrake"
|
|
echo " and run script..."
|
|
echo
|
|
echo "OPTION:"
|
|
echo " -h display this help"
|
|
echo " -i source folder (recursive)"
|
|
echo " -o destination folder"
|
|
echo " -p preset HandBrake"
|
|
echo
|
|
echo -e "Example: ${italic}./handbrake_for_plex.sh -i $HOME/Downloads -o $HOME/Images -p 'Apple 720p30 Surround'${reset}"
|
|
echo
|
|
echo -e "To known Preset, run ${italic}HandBrakeCLI --preset-list${reset}"
|
|
echo
|
|
exit 0
|
|
}
|
|
|
|
notification() {
|
|
#path_img=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
|
|
if [ "$3" -eq 0 ];
|
|
then
|
|
sound="Glass"
|
|
#image="$path_img/success.png"
|
|
#image="$path_img/HandBrake.icns"
|
|
else
|
|
sound="Basso"
|
|
#image="$path_img/error.png"
|
|
fi
|
|
|
|
if [[ "$OSTYPE" == "linux-gnu" ]] && [ -x "$(command -v zenity)" ]; then
|
|
zenity --title="$1" --notification --text="$2"
|
|
elif [[ "$OSTYPE" == "darwin"* ]] && [ -x "$(command -v terminal-notifier)" ]; then
|
|
### -appIcon ne marche avec BigSur
|
|
# terminal-notifier -title "$1" -message "$2" -sound "$sound" -contentImage "$image" -activate "com.colliderli.iina"
|
|
terminal-notifier -title "$1" -message "$2" -sound "$sound" -appIcon "https://sur-le-sentier.fr/HandBrake.png" -activate "com.colliderli.iina"
|
|
# org.galad.Subler.plist com.colliderli.iina.plist -appIcon http://vjeantet.fr/images/logo.png
|
|
fi
|
|
}
|
|
|
|
while getopts "h?i:o:p:" opt; do
|
|
case "$opt" in
|
|
h|\?)
|
|
showHelp
|
|
exit 0
|
|
;;
|
|
i) input_path="$OPTARG"
|
|
;;
|
|
o) output_path="$OPTARG"
|
|
;;
|
|
p) profile="$OPTARG"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Reset OPTIND
|
|
shift $((OPTIND-1))
|
|
|
|
|
|
# https://stackoverflow.com/questions/59895/how-can-i-get-the-directory-where-a-bash-script-is-located-from-within-the-scrip
|
|
#DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
|
|
#SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
#DIR_SCRIPT=$(dirname -- "$( readlink -f -- "$0"; )")
|
|
|
|
####
|
|
# Configuration
|
|
|
|
# Source video folder
|
|
[[ "$input_path" == "" ]] && SRC="$HOME/Downloads" || SRC="$input_path"
|
|
|
|
# Destination video folder
|
|
[[ "$output_path" == "" ]] && DEST="$HOME/Movies" || DEST="$output_path"
|
|
|
|
# Extension video file
|
|
DEST_EXT=mp4
|
|
|
|
# Handbrake preset
|
|
[[ "$profile" == "" ]] && PRESET="Apple 720p30 Surround" || PRESET="$profile"
|
|
|
|
# Only files larger than $MAXSIZE will be processed (> 30Mo)
|
|
MAXSIZE=30000000
|
|
#MAXSIZE=300
|
|
|
|
# Open converted video file in an application
|
|
APP="Subler"
|
|
|
|
SUBTITLE_LIST="eng,fre"
|
|
|
|
# log
|
|
# this reduce handbrake verbosity
|
|
logfile=/tmp/HandBrake.log
|
|
|
|
#Move to trash after conversion
|
|
trash=true
|
|
|
|
|
|
###
|
|
|
|
echo "_ _ ____ _ _ ___ ___ ____ ____ _ _ ____ ____ ____ ____ ___ _ ____ _ _ ";
|
|
echo "|__| |__| |\ | | \ |__] |__/ |__| |_/ |___ |___ | | |__/ |__] | |___ \/ ";
|
|
echo "| | | | | \| |__/ |__] | \ | | | \_ |___ | |__| | \ | |___ |___ _/\_ ";
|
|
echo " ";
|
|
echo " ";
|
|
echo " ";
|
|
|
|
version=$(ls /opt/homebrew/Cellar/handbrake 2>/dev/null)
|
|
if [ "$version" != "" ]; then
|
|
HANDBRAKE_CLI="/opt/homebrew/Cellar/handbrake/$version/bin/HandBrakeCLI"
|
|
echo -e "${bold}HandBrake $version${reset}"
|
|
echo -e "$HANDBRAKE_CLI\n"
|
|
else {
|
|
cli=$(which HandBrakeCLI)
|
|
if [ "$cli" != "" ]; then
|
|
HANDBRAKE_CLI="$cli"
|
|
version=$("$HANDBRAKE_CLI" --version 2>/dev/null | sed -n '1p')
|
|
echo -e "${bold}HandBrake $version${reset}"
|
|
echo -e "$HANDBRAKE_CLI\n"
|
|
else
|
|
echo -e "${red}HandBrake not installed!${reset}\n"
|
|
exit 1
|
|
fi
|
|
}
|
|
fi
|
|
|
|
echo -e "Source folder: ${italic}$SRC${reset}"
|
|
echo -e "Destination folder: ${italic}$DEST${reset}"
|
|
echo -e "HandBrake Profile: ${italic}$PRESET${reset}"
|
|
|
|
# nok en bash, ok en zsh
|
|
#ls -1 **/*.(mkv|mp4)
|
|
#ls **/*.(mkv|avi|mp4|m4v)
|
|
#ls "$HOME/Downloads"/**/*.(mkv|avi|mp4|m4v)
|
|
|
|
#ls "$SRC"/**/*.{mkv,avi,mp4,m4v}
|
|
|
|
count=0
|
|
# Series: SxxEyy
|
|
REGEX="([sS]([0-9]{2,}|[X]{2,})[eE]([0-9]{2,}|[Y]{2,}))"
|
|
# Films: 2
|
|
REGEX2="[0-9]{4}"
|
|
|
|
movies=()
|
|
for FILE in "${SRC}"/**/*.{mkv,avi,mp4,m4v}
|
|
do
|
|
# Get file size
|
|
FILESIZE=$(stat -c%s "$FILE")
|
|
|
|
if (( FILESIZE > MAXSIZE )); then
|
|
movies+=("${FILE}")
|
|
fi
|
|
done
|
|
nb_movies=${#movies[@]}
|
|
|
|
for FILE in "${movies[@]}"
|
|
do
|
|
filename=$(basename "$FILE")
|
|
#extension=${filename##*.}
|
|
filename=${filename%.*}
|
|
|
|
|
|
: <<'END_COMMENT'
|
|
https://stackoverflow.com/questions/41231998/mediainfo-cli-command-line-interface-syntax-teaching-me-once-for-all
|
|
media=$(mediainfo --Output=file:///$SCRIPT_DIR/template.txt "$FILE")
|
|
l=$(echo "$media" | sed -n '1p')
|
|
info=$(sed "1s/.*/\\${bold}$l\\${reset}/" <<< "$media")
|
|
echo -e "$info\n"
|
|
END_COMMENT
|
|
|
|
|
|
# Séries
|
|
if [[ $filename =~ $REGEX ]]; then
|
|
MATCH="${BASH_REMATCH[1]}"
|
|
# Remplace les . par des espaces
|
|
e=$(echo "${filename%$MATCH*}" | sed 's/\./\ /g' | xargs)
|
|
# Capitalise chaque mot
|
|
f=( $e )
|
|
g=${f[@]^}
|
|
# Met en majuscule SxxExx
|
|
new_name="$g - ${MATCH^^}.$DEST_EXT"
|
|
# Films
|
|
elif [[ $filename =~ $REGEX2 ]]; then
|
|
MATCH2="${BASH_REMATCH[0]}"
|
|
e=$(echo "${filename%$MATCH2*}" | sed 's/\./\ /g' | xargs)
|
|
new_name="$e ($MATCH2).$DEST_EXT"
|
|
else
|
|
echo "Could not find SXXEYY pattern"
|
|
new_name="$filename"
|
|
continue
|
|
fi
|
|
|
|
if ! command -v mediainfo &> /dev/null; then
|
|
echo -e "${bold}mediainfo${reset} could not be found !\n"
|
|
echo -e "You should install ${bold}mediainfo${reset}:\n"
|
|
echo -e " - brew install mediainfo"
|
|
echo -e ""
|
|
else
|
|
|
|
infos=$(mediainfo "$FILE" --output=JSON | jq -s 'map({ VideoCount: .media.track[0].VideoCount, AudioCount: .media.track[0].AudioCount, TextCount: .media.track[0].TextCount, MenuCount: .media.track[0].MenuCount, FormatFichier: .media.track[0].Format, FileSize: .media.track[0].FileSize, Duration: .media.track[0].Duration, FormatVideo: .media.track[1].Format, Format_Profile: .media.track[1].Format_Profile, Format_Level: .media.track[1].Format_Level, "CodecVideo": .media.track[1].CodecID, Width: .media.track[1].Width, Height: .media.track[1].Height, FormatAudio: .media.track[2].Format, FormatAdditionalFeatures: .media.track[2].Format_AdditionalFeatures, CodecAudio: .media.track[2].CodecID, TitleAudio: .media.track[2].Title, LanguageAudio: .media.track[2].Language, DefaultAudio: .media.track[2].Default, FormatText: .media.track[3].Format, CodecText: .media.track[3].CodecID, LanguageText: .media.track[3].Language, DefaultText: .media.track[3].Default, Menu: .media.track[4].extra})')
|
|
|
|
# General
|
|
#nb_video=$(echo "$infos" | jq -j '.[] | .VideoCount')
|
|
nb_audio=$(echo "$infos" | jq -j '.[] | .AudioCount')
|
|
if [[ "$nb_audio" == "null" ]]; then nb_audio=0; fi
|
|
nb_text=$(echo "$infos" | jq -j '.[] | .TextCount')
|
|
if [[ "$nb_text" == "null" ]]; then nb_text=0; fi
|
|
nb_menu=$(echo "$infos" | jq -j '.[] | .MenuCount')
|
|
if [[ "$nb_menu" == "null" ]]; then nb_menu=0; fi
|
|
format_fichier=$(echo "$infos" | jq -j '.[] | .FormatFichier')
|
|
filesize=$(echo "$infos" | jq -j '.[] | .FileSize' | numfmt --to=si --format "%8.2f" | xargs)
|
|
#fsize=$(numfmt --to iec --format "%8.2f" "$filesize")
|
|
duree=$(echo "$infos" | jq -j '.[] | .Duration' | awk -F "." '{print $1}' | awk '{printf "%d:%02d:%02d", $1/3600, ($1/60)%60, $1%60}' | xargs)
|
|
|
|
# Video
|
|
format_video=$(echo "$infos" | jq -j '.[] | .FormatVideo')
|
|
format_profile=$(echo "$infos" | jq -j '.[] | .Format_Profile')
|
|
format_level=$(echo "$infos" | jq -j '.[] | .Format_Level')
|
|
codec_video=$(echo "$infos" | jq -j '.[] | .CodecVideo')
|
|
width=$(echo "$infos" | jq -j '.[] | .Width')
|
|
height=$(echo "$infos" | jq -j '.[] | .Height')
|
|
|
|
# Audio
|
|
format_audio=$(echo "$infos" | jq -j '.[] | .FormatAudio')
|
|
format_addition=$(echo "$infos" | jq -j '.[] | .FormatAdditionalFeatures')
|
|
if [[ "$format_addition" == "null" ]]; then format_addition=""; fi
|
|
codec_audio=$(echo "$infos" | jq -j '.[] | .CodecAudio')
|
|
title_audio=$(echo "$infos" | jq -j '.[] | .TitleAudio')
|
|
language_audio=$(echo "$infos" | jq -j '.[] | .LanguageAudio')
|
|
if [[ "$language_audio" == "null" ]]; then language_audio=""; fi
|
|
default_audio=$(echo "$infos" | jq -j '.[] | .DefaultAudio')
|
|
if [[ "$default_audio" == "null" ]]; then default_audio=""; fi
|
|
|
|
# Text
|
|
format_text=$(echo "$infos" | jq -j '.[] | .FormatText')
|
|
codec_text=$(echo "$infos" | jq -j '.[] | .CodecText')
|
|
language_text=$(echo "$infos" | jq -j '.[] | .LanguageText')
|
|
default_text=$(echo "$infos" | jq -j '.[] | .DefaultText')
|
|
|
|
# Menu
|
|
menu=$(echo "$infos" | jq -j '.[] | .Menu' | sed '1d;$d')
|
|
m=""
|
|
while IFS= read -r line
|
|
do
|
|
t=$(echo "$line" | awk -F": " '{print $1}')
|
|
c=$(echo "$line" | awk -F": " '{print $2}')
|
|
|
|
tt=$(echo "$t" | sed -n '1 s/"//gp' | xargs | sed 's/^_//' | sed 's/_/h/1' | sed 's/_/mm/1' | sed 's/_/s/1' | sed 's/s.*//')
|
|
cc=$(echo "$c" | tr -d '"' | xargs | awk -F ":" '{print $2}' | sed 's/,$//' | sed 's/^/ /')
|
|
|
|
m+="$cc : $tt\n"
|
|
done <<< "$menu"
|
|
|
|
echo -e "\n\n${bold}(${red}$(( count + 1 ))${reset}${bold} / $nb_movies) - $filename${reset}"
|
|
|
|
echo -e "\n${bold}General:${reset}"
|
|
printf " %-20s %-35s \n" "Format de fichier:" "${format_fichier}"
|
|
printf " %-20s %-35s \n" "Taille de fichier:" "${filesize}"
|
|
printf " %-21s %-35s \n" "Duree:" "${duree}"
|
|
|
|
echo -e "\n${bold}Video:${reset}"
|
|
printf " %-21s %-35s \n" "Format video:" "${format_video}"
|
|
printf " %-20s %-35s \n" "Profile:" "${format_profile}"
|
|
printf " %-20s %-35s \n" "Level:" "${format_level}"
|
|
printf " %-20s %-35s \n" "Codec:" "${codec_video}"
|
|
printf " %-20s %-35s \n" "Dimensions:" "${width} x ${height}"
|
|
|
|
echo -e "\n${bold}Audio:${reset}"
|
|
printf " %-20s %-35s \n" "Format audio:" "${format_audio}"
|
|
printf " %-20s %-35s \n" "Format additionnel:" "${format_addition}"
|
|
printf " %-20s %-35s \n" "Codec:" "${codec_audio}"
|
|
printf " %-20s %-35s \n" "Titre:" "${title_audio}"
|
|
printf " %-20s %-35s \n" "Language:" "${language_audio}"
|
|
printf " %-20s %-35s \n" "Defaut:" "${default_audio}"
|
|
|
|
if [ "$nb_text" -ge 1 ]; then
|
|
echo -e "\n${bold}Text:${reset}"
|
|
printf " %-20s %-35s \n" "Format text:" "${format_text}"
|
|
printf " %-20s %-35s \n" "Codec:" "${codec_text}"
|
|
printf " %-20s %-35s \n" "Language:" "${language_text}"
|
|
printf " %-20s %-35s \n" "Defaut:" "${default_text}"
|
|
fi
|
|
|
|
if [ "$nb_menu" -ge 1 ]; then
|
|
echo -e "\n${bold}Menu:${reset}"
|
|
echo -e "$m"
|
|
fi
|
|
|
|
fi # if mediainfo installed
|
|
|
|
|
|
file_export="$DEST"/"$new_name"
|
|
|
|
if [ ! -f "$file_export" ]; then
|
|
#echo -e "\n${yellow}Convert $FILE${reset} ${bold}->${reset} ${green}$file_export${reset}"
|
|
z="\n${yellow}Convert $FILE${reset} ${bold}->${reset} ${green}$file_export${reset}"
|
|
|
|
if [ "$nb_text" -ge 1 ] && [[ $SUBTITLE_LIST =~ ${language_text} ]]; then
|
|
echo -e "$z (with ${bold}${language_text}${reset} subtitle track)"
|
|
$HANDBRAKE_CLI -i "$FILE" -o "$file_export" "$PRESET" --subtitle-lang-list "$SUBTITLE_LIST" --all-subtitles 2> $logfile
|
|
else
|
|
echo -e "$z"
|
|
$HANDBRAKE_CLI -i "$FILE" -o "$file_export" "$PRESET" 2> $logfile
|
|
fi
|
|
echo
|
|
|
|
result=$?
|
|
if [ "$result" = 0 ]; then
|
|
notification "HandBrake for Plex" "$new_name available in $DEST" $result
|
|
fi
|
|
|
|
|
|
# Open DEST file in an app
|
|
if [ "$APP" != "" ]; then
|
|
if [[ $(command -v mdfind) == "" ]]; then
|
|
echo -e "\n${red}mdfind not find ! mdfind is a part macOS.${reset}"
|
|
else
|
|
x=$(mdfind -name "$APP" kind:application)
|
|
if [ "$x" != "" ]; then
|
|
if [ -f "$file_export" ]; then
|
|
echo -e "\n${bold}Opening $file_export in $APP...${reset}"
|
|
open -a "$APP" "$file_export"
|
|
fi
|
|
else
|
|
echo -e "\n${red}$APP was not found...${reset}"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Move SRC file to trash
|
|
parent_folder=${FILE%/*}
|
|
if [ "$trash" = true ] && [[ "$OSTYPE" == "darwin"* ]]; then
|
|
echo -e "\n${italic}Move ${filename} to trash...${reset}"
|
|
osascript -e "tell application \"Finder\" to delete POSIX file \"${FILE}\"" >/dev/null
|
|
fi
|
|
if [ "$trash" = true ] && [[ "$OSTYPE" == "linux-gnu"* ]] && [[ $(command -v gio) != "" ]]; then
|
|
echo -e "\n${italic}Move ${filename} to trash...${reset}"
|
|
gio trash "$FILE" >/dev/null
|
|
fi
|
|
|
|
[ "$(echo "${parent_folder}/"*)" = "${parent_folder}/*" ] && rm -rf "${parent_folder}";
|
|
|
|
echo ""
|
|
((count++))
|
|
|
|
else
|
|
echo -e "\n${green}$file_export already transcoded !${reset}\n"
|
|
|
|
fi
|
|
|
|
FILESIZE=
|
|
|
|
done
|
|
|
|
|
|
if [ "$count" -eq 0 ]; then
|
|
echo -e "\n${red}No file to transcode !${reset}"
|
|
else
|
|
echo -e "\n${green}${count} files successfully transcoded !${reset}"
|
|
fi
|
|
|
|
|