Comme convenu :
ajout des informations globales et unitaires suivante :
- heure de début de traitement
- durée de traitement
- fin de traitement prévisionnelle
#!/bin/bash
FIC_PARAM=~/.pffmpegrc
trap "finScript" SIGINT SIGTERM
function restaure_curseur
{
setterm -cursor on
setterm -linewrap on
}
function finScript
{
echo
echo "Traitement interrompu." >&2
restaure_curseur
exit 1
}
function formaterSecondes
{
secondes="${1}"
format="$(awk ' { secondes=$0; heure=int(secondes/3600); minute=int((secondes-3600*heure)/60); seconde=secondes-3600*heure-60*minute;print heure" "minute " " seconde } ' <<< ${secondes})"
elements=( ${format} )
for((idx=0;idx<${#elements[@]};idx++))
do
# si un seul caractère alors on ajoute 0. (pas de test au delas de 2 caractères pour une durée > 99h59min59sec
if [ ${#elements[${idx}]} -eq 1 ]; then
elements[${idx}]="0${elements[${idx}]}"
fi
done
echo "${elements[0]}:${elements[1]}:${elements[2]}"
}
function ajuste_longueur
{
texte="$1"
longueur=$2
caractere="${3:-" "}"
while [ ${#texte} -lt ${longueur} ]
do
texte="${texte}${caractere}"
done
texte="${texte:0:${longueur}}"
echo "${texte}"
}
function ajuste_multiligne
{
texte="$1"
longueur=$2
caractere="${3:-" "}"
local chaineResultat=""
while [ ${#texte} -gt ${longueur} ];
do
if [ ! "${chaineResultat}" ]; then
chaineResultat="${texte:0:${longueur}}"
else
chaineResultat="${chaineResultat}\n${texte:0:${longueur}}"
fi
texte="${texte:${longueur}}"
done
texte="$(ajuste_longueur "${texte}" ${longueur})"
if [ ! "${chaineResultat}" ]; then
chaineResultat="${texte}"
else
chaineResultat="${chaineResultat}\n${texte}"
fi
echo "${chaineResultat}"
}
function format_ligne
{
local ligneType="${1}"
local dureeVide="${2}"
shift 2
for((idx=1;idx<=5;idx++))
do
ligneType="${ligneType/${dureeVide}/ $1 }"
shift
done
ligneType="${ligneType/ xxx % / ${1} }"
echo "${ligneType}"
}
function affiche_evolution
{
type_conv="${1}"
options_conv="${2}"
nb_fichier="${3}"
duree_totale="${4}"
duree_totaleHHMMSS="$(formaterSecondes ${duree_totale})"
secondes_debut="${5}"
# Conversion en HH:MM:SS des secondes depuis @
heure_debut="$(date +'%H:%M:%S' -d "@${secondes_debut}")"
i=0
fichier=""
ligneFichier=""
ligneDuree=""
setterm -cursor off
setterm -linewrap off
nbCols=$(($(tput cols)-1))
ligneTiret=$(ajuste_longueur "" ${nbCols} "-")
dureeVide=" -------- "
dureeVierge=" "
ligneInfoType="|${dureeVide}|${dureeVide}|${dureeVide}|${dureeVide}|${dureeVide}| xxx % |"
ligneInfoVide="${ligneInfoType//[-x%]/ }"
nbColNomFichier=$((${nbCols}-${#ligneInfoType}-3))
# affichage des informations de conversion (static)
echo -e "\n${ligneTiret}"
echo "$(ajuste_longueur "| Type de conversion : ${type_conv}" $((${nbCols}-1)))|"
uneChaine="Options de conversion : ${options_conv}"
uneChaine="$(ajuste_multiligne "${uneChaine}" $((${nbCols}-4)))"
echo -e "| ${uneChaine//\\n/ |\\n| } |"
echo "${ligneTiret}"
# affichage de la légende
echo "$(ajuste_longueur "| Légende : " $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| Fichier : Fichier en cours de conversion" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| HDT : Heure de Début de Traitement" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| DTE : Durée de Traitement Ecoulée" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| HFP : Heure de Fin de traitement Prévisionnelle" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| DTF : Durée à Traiter du Fichier" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| DCF : Durée Convertie du Fichier" $((${nbCols}-1)))|"
echo "$(ajuste_longueur "| EVO : EVOlution du traitement" $((${nbCols}-1)))|"
echo "${ligneTiret}"
# affichage entete
echo "| $(ajuste_longueur "Fichier" ${nbColNomFichier}) $(format_ligne "${ligneInfoType}" "${dureeVide}" " HDT " " DTE " " HFP " " DTF " " DCF " " EVO ")"
echo "${ligneTiret}"
while read infos
do
oldIFS="${IFS}"
IFS=";"
infos=( ${infos} )
numFichier="${infos[0]}"
#nomFichier="$(ajuste_longueur ${infos[1]} 300 "x")"
nomFichier="#${numFichier} - ${infos[1]}"
dureeFichierTraitee="${infos[2]}"
dureeFichierTotale="${infos[3]}"
dureeTotaleTraitee="${infos[4]}"
secondes_fichier="${infos[5]}"
debut_fichier="$(date +'%H:%M:%S' -d "@${secondes_fichier}")"
IFS="${oldIFS}"
# restauration de la position du curseur au nivau des inforamtions de la progression
if [ ${i} -eq 1 ]; then
if [ "${fichier}" != "${nomFichier}" ]; then
chaineRetour="\033[1A"
else
chaineRetour="\033[${nbLigne}A"
fi
echo -en "\r${chaineRetour}"
echo -en "\033[$((nbColNomFichier+2))C"
fi
secondes_traitement="$(date +'%s')"
delai_total=$((${secondes_traitement}-${secondes_debut}))
delai_totalHHMMSS="$(formaterSecondes ${delai_total})"
dureeFichierTraiteeHHMMSS="$(formaterSecondes ${dureeFichierTraitee})"
dureeFichierTotaleHHMMSS="$(formaterSecondes ${dureeFichierTotale})"
dureeTotaleTraiteeHHMMSS="$(formaterSecondes ${dureeTotaleTraitee})"
delai_fichier=$((${secondes_traitement}-${secondes_fichier}))
delai_fichierHHMMSS="$(formaterSecondes ${delai_fichier})"
pctTotal="$(awk '{printf("%1.0f",$1*100/$2)}' <<< "${dureeTotaleTraitee} ${duree_totale}")"
heureFinTotalHHMMSS="--:--:--"
if [ ${pctTotal} -ne 0 ]; then
secTotalFin="$(awk '{printf("%1.0f",$1*100/$2)}' <<< "${delai_total} ${pctTotal}")"
((secTotalFin+=secondes_debut))
heureFinTotalHHMMSS="$(date +'%H:%M:%S' -d "@${secTotalFin}")"
fi
pctTotal=" ${pctTotal} %"
pctTotal="${pctTotal:$((${#pctTotal}-5))}"
pctCourant="$(awk '{printf("%1.0f",$1*100/$2)}' <<< "${dureeFichierTraitee} ${dureeFichierTotale}")"
heureFinFichierHHMMSS="--:--:--"
if [ ${pctCourant} -ne 0 ]; then
secFichierFin="$(awk '{printf("%1.0f",$1*100/$2)}' <<< "${delai_fichier} ${pctCourant}")"
((secFichierFin+=secondes_fichier))
heureFinFichierHHMMSS="$(date +'%H:%M:%S' -d "@${secFichierFin}")"
fi
pctCourant=" ${pctCourant} %"
pctCourant="${pctCourant:$((${#pctCourant}-5))}"
if [ "${fichier}" != "${nomFichier}" ]; then
# changement de fichier, on affiche le nouveau nom de fichier
uneChaine="$(ajuste_multiligne "${nomFichier}" ${nbColNomFichier})"
echo -ne "\r| ${uneChaine//\\n/ \\n| }"
nbLigne="$(echo -e "${uneChaine}"|wc -l)"
nbLigne=$((nbLigne+2))
# on remonte de nbLigne-3 (i.e si l'affichage du nom de fichier s'effectue sur plusieurs lignes)
if [ ${nbLigne} -gt 3 ]; then
chaineRetour="\033[$((nbLigne-3))A"
echo -en "${chaineRetour}"
fi
fi
echo -e " $(format_ligne "${ligneInfoType}" "${dureeVide}" "${debut_fichier}" "${delai_fichierHHMMSS}" "${heureFinFichierHHMMSS}" "${dureeFichierTotaleHHMMSS}" "${dureeFichierTraiteeHHMMSS}" "${pctCourant}")"
ligneSep=""
if [ "${fichier}" != "${nomFichier}" ]; then
ligneSep="\r\033[$((nbColNomFichier+3))C${ligneInfoVide}"
fi
for((idx=4;idx<=${nbLigne};idx++));
do
echo -e "${ligneSep}"
done;
fichier="${nomFichier}"
echo "${ligneTiret}"
echo -e "| $(ajuste_longueur "Total (${nb_fichier} fichier(s))" ${nbColNomFichier}) $(format_ligne "${ligneInfoType}" "${dureeVide}" "${heure_debut}" "${delai_totalHHMMSS}" "${heureFinTotalHHMMSS}" "${duree_totaleHHMMSS}" "${dureeTotaleTraiteeHHMMSS}" "${pctTotal}")"
echo -n "${ligneTiret}"
i=1
done
echo
restaure_curseur
}
# tests d'usage
if [ $# -lt 2 ]; then
cat <<EOF >&2
Nombre de paramètres incorrectes.
$(basename "$0") : TypeDeConversion ListeFichiers
TypeDeConversion : Défini dans le fichier ~/.pffmpegrc, il fait le lien entre les paramètres ffmpeg à appliquer et l'extension souhaitée.
ListeFichiers : Liste des fichiers à convertir.
Le fichier ~/.pffmpegrc se compose de 3 colonnes séparées par un ";".
1ère colonne : TypeDeConversion
2nde colonne : extension souhaitée
3ème colonne : paramètres ffmpeg. Ne pas y inclure le paramètre "-i" car "$(basename "$0")" s'en charge pour le positionner en 1ère position des paramètres. Il est cependant possible de spécifier sa position avec le mot <SOURCE>.
Exemple de contenu :
#type de conversion video pour psp
psp;mp4;-threads 4 -y <SOURCE> -r 29.97 -acodec libfaac -ab 128kb -ac 2 -ar 48000 -vcodec libx264 -level 21 -b 768kb -coder 1 -f psp -flags +loop -cmp +chroma -trellis 2 -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me_method umh -subq 6 -trellis 1 -refs 3 -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10 -qmax 51 -qdiff 4 -g 250 -s 480x272
# type de conversion mp3
audio;mp3;-y -ar 44100 -ab 160 -ac 2
Exemple d'utilisation :
$(basename "$0") psp /video/*.avi
EOF
exit 1
fi
typeConv="$1"
shift
# récupération extension finale et ligne de commande correspondant au type de conversion
oldIFS="${IFS}"
IFS=";"
infosffmpeg=( $(grep "^${typeConv};" "${FIC_PARAM}"|head -1) )
if [ ${#infosffmpeg[@]} -ne 3 ]; then
echo "Type de conversion non trouvée !" >&2
exit 1
fi
extffmpeg="${infosffmpeg[1]}"
cmdffmpeg="${infosffmpeg[2]}"
IFS="${oldIFS}"
# récupération de la durée totale des fichiers à convertir
dureeTotale=0
indice=0
for fichier in "$@"
do
if [ ! -f "${fichier}" ]; then
echo "'${fichier}' n'est pas un fichier valide !" >&2
exit 1
fi
dureeFichier[${indice}]=0
while read duration
do
duration=( ${duration//:/ } )
duree=$(bc <<< "${duration[0]}*3600 + ${duration[1]}*60 + ${duration[2]}")
dureeFichier[${indice}]=$(bc <<< "${dureeFichier[${indice}]} + ${duree}")
done < <(ffmpeg -i "${fichier}" 2>&1| grep Duration | egrep -o "[0-9]{2}:[0-9]{2}:[0-9]{2}")
dureeTotale=$( bc <<< "${dureeFichier[${indice}]} + ${dureeTotale}")
((indice++))
done
# conversion des fichiers
dureeEcoulee=0
indice=0
secondes_debut="$(date +'%s')"
for fichier in "$@"
do
rm -f "${fichier}.${extffmpeg}" >&/dev/null
SOURCE="-i \"${fichier}\""
if [[ "${cmdffmpeg}" =~ \<SOURCE\> ]]; then
cmd="${cmdffmpeg/<SOURCE>/${SOURCE}}"
else
cmd="${SOURCE} ${cmdffmpeg}"
fi
# numFichier;nomFichier;dureeEcouleeFichier;dureeTotaleFichier;dureeEcouleeTotale;secondes_fichier (nb secondes depuis @)
eval "ffmpeg ${cmd} \"${fichier}.${extffmpeg}\"" 2>&1 | awk -v secondes_fichier="$(date +'%s')" -v numFichier=$((${indice}+1)) -v dureeTotaleFichier=${dureeFichier[${indice}]} -v dureeEcoulee=${dureeEcoulee} -v dureeTotale=${dureeTotale} -v unFichier="${fichier}" -v dureeFichier=${dureeFichier[${indice}]} --re-interval ' BEGIN {RS="\r"; print numFichier";"unFichier";"0";"dureeTotaleFichier";"dureeEcoulee";"secondes_fichier ; fflush();} /time=.*/ {p=match($0,/time.*=/,r); duree=r[0]; gsub(/[[:alpha:]=[:blank:]]/,"",duree);duree=int(duree); pctEncode=int(duree*100/dureeFichier); print numFichier";"unFichier";"duree";"dureeTotaleFichier";"duree+dureeEcoulee";"secondes_fichier; fflush(); }'
dureeEcoulee=$(( dureeFichier[${indice}] + dureeEcoulee ))
((indice++))
done | affiche_evolution "${typeConv}" "${cmdffmpeg}" "$#" "${dureeTotale}" "${secondes_debut}"
EDIT :
+ suppression affichage curseur (permet un meilleur affichage)
+ gestion de l'arrêt du script pour rétablir le curseur
+ Amélioration du rendu des informations (au détriment des perfs)
+ Modification du mécanisme d'affichage pour tenter de gagner en perf.
-----
+ 23/06/2009 : Refonte de l'interface afin d'avoir une historisation des fichiers traités