Compare commits
No commits in common. "434152daba95cb8d724bda8cdc45ba9c7ca74c6a" and "69d0b409e9203e082ab80cb6d761d8cd9479d958" have entirely different histories.
434152daba
...
69d0b409e9
@ -3,6 +3,7 @@
|
||||
* URL: https://framagit.org/ScriptFanix/AtOM/
|
||||
* Author: Vincent Riquer <vincent+prog.atom@riquer.fr>
|
||||
* Copyright/left: 2012-2013,2015,2025 Vincent Riquer - GPLv3
|
||||
- except: transogg: WTFPL 2.0
|
||||
|
||||
## Dependencies
|
||||
### Required:
|
||||
|
||||
503
transogg
Executable file
503
transogg
Executable file
@ -0,0 +1,503 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat <<-EOF
|
||||
This script is buggy and may destroy data
|
||||
DON'T USE IT!
|
||||
|
||||
AtOM will be a clean and safe rewrite of this dirty hack.
|
||||
|
||||
I repeat: DON'T use this script.
|
||||
EOF
|
||||
exit
|
||||
|
||||
source /etc/transogg.conf
|
||||
|
||||
[ ! -d "$TEMPDIR" ] && mkdir -p "$TEMPDIR"
|
||||
|
||||
# log errors
|
||||
exec 2> $TEMPDIR/debug-$$.log
|
||||
|
||||
set -E
|
||||
|
||||
MyPID=$$
|
||||
|
||||
tty=$(who -m|awk '{print $2}')
|
||||
|
||||
cleanup() {
|
||||
pkill -t $tty find||true
|
||||
unset files
|
||||
export killed=1
|
||||
}
|
||||
|
||||
export -f cleanup
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
$0 [-D] [-n <instances>] [-F] [-s <source directory>] [-t <target directory>]
|
||||
|
||||
-n <instances>: run <instances> simultaneous processes (overrides config
|
||||
file)
|
||||
-l <max load>: Don't start transcoding if the load average reaches <max
|
||||
load>
|
||||
-T <time>: time before raising instance number again after reaching max
|
||||
load
|
||||
-F: ignore any existing timestamp file (useful if you change target
|
||||
quality)
|
||||
-D: increase debug level (produces potentially huge log files in
|
||||
$TEMPDIR)
|
||||
-c <conf-file>: Alternate configuration file
|
||||
EOF
|
||||
}
|
||||
|
||||
trap cleanup 1 2 15 EXIT
|
||||
|
||||
declare -i DEBUG=0
|
||||
|
||||
while getopts 'l:FhiDs:t:T:c:' opt
|
||||
do
|
||||
case $opt in
|
||||
s) ORIGDIR=$OPTARG ;;
|
||||
t) DESTDIR=$OPTARG ;;
|
||||
l) TARGETLOAD=$OPTARG
|
||||
;;
|
||||
F) rm -f "$TIMESTAMP"
|
||||
;;
|
||||
h) usage ; exit 0 ;;
|
||||
T) LOADTIME=$OPTARG ;;
|
||||
D) DEBUG+=1; set -x ;;
|
||||
c) source "$OPTARG" ;;
|
||||
*) exit 127
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
(( DEBUG >= 2 )) && set -v
|
||||
|
||||
COLUMNS=$(tput cols)
|
||||
LINES=$(tput lines)
|
||||
trap 'COLUMNS=$(tput cols) LINES=$(tput lines)' WINCH
|
||||
declare -a children
|
||||
declare -i filenum=0
|
||||
declare -i lastid=-1
|
||||
FIFO=/tmp/transogg-$UID-$MyPID-status
|
||||
IDFIFO=/tmp/transogg-$UID-$MyPID-finished
|
||||
shopt -s extglob
|
||||
declare -i lastINSTchange=0
|
||||
((instances = TARGETLOAD / 2))
|
||||
|
||||
[ -d "$TEMPDIR" ] \
|
||||
|| mkdir -p "$TEMPDIR" \
|
||||
|| exit 1
|
||||
|
||||
[ -d "$DESTDIR" ] \
|
||||
|| mkdir -p "$DESTDIR" \
|
||||
|| exit 1
|
||||
|
||||
[ -f "$TIMESTAMP" ] \
|
||||
|| touch -t 197001010100 "$TIMESTAMP"
|
||||
|
||||
case $FORMAT in
|
||||
ogg)
|
||||
function encode {
|
||||
nice -n $NICENESS ionice -c3 \
|
||||
oggenc \
|
||||
-Q \
|
||||
-a "${artist:-?}" \
|
||||
-l "${album:-?}" \
|
||||
-N "${tracknum}${tracktotal/#//}" \
|
||||
-t "${title:-$(basename "$1")}" \
|
||||
-q $QUALITY \
|
||||
-d "$year" \
|
||||
-G "$genre" \
|
||||
-c DISCNUMBER="$disc" \
|
||||
-o "$2" \
|
||||
$tmpfile \
|
||||
2> /dev/null
|
||||
}
|
||||
;;
|
||||
mp3)
|
||||
function encode {
|
||||
nice -n $NICENESS ionice -c3 \
|
||||
lame \
|
||||
--quiet \
|
||||
--ta "${artist:-?}" \
|
||||
--tl "${album:-?}" \
|
||||
--tn "${tracknum}${tracktotal/#//}" \
|
||||
--tt "${title:-$(basename "$1")}" \
|
||||
-v \
|
||||
--abr $BITRATE \
|
||||
--ty "$year" \
|
||||
--tg "$genre" \
|
||||
$tmpfile \
|
||||
"$2" \
|
||||
2> /dev/null
|
||||
}
|
||||
;;
|
||||
*)
|
||||
exit 127
|
||||
;;
|
||||
esac
|
||||
|
||||
gettag() {
|
||||
echo -e "$1" \
|
||||
| egrep -i '^'${2}= \
|
||||
| cut -d = -f 2
|
||||
}
|
||||
|
||||
mpc_info() {
|
||||
infos=$(ionice -c3 \
|
||||
strings "$1" \
|
||||
| egrep -A1 'artist|album|title|track|year|genre')
|
||||
title=$(echo -e "$infos"|sed -n /title/I {n;p})
|
||||
artist=$(echo -e "$infos"|sed -n /artist/I {n;p})
|
||||
track=$(echo -e "$infos"|sed -n /track/I {n;p})
|
||||
album=$(echo -e "$infos"|sed -n /album/I {n;p})
|
||||
year=$(echo -e "$infos"|sed -n /year/I {n;p})
|
||||
genre=$(echo -e "$infos"|sed -n /genre/I {n;p})
|
||||
unset infos
|
||||
}
|
||||
|
||||
flac_info() {
|
||||
infos=$(ionice -c3 \
|
||||
metaflac \
|
||||
--show-tag=TITLE \
|
||||
--show-tag=ARTIST \
|
||||
--show-tag=ALBUM \
|
||||
--show-tag=TRACKNUMBER \
|
||||
--show-tag=TRACKTOTAL \
|
||||
--show-tag=DATE \
|
||||
--show-tag=DISCNUMBER \
|
||||
--show-tag=GENRE \
|
||||
"$1")
|
||||
|
||||
artist=$(gettag "$infos" artist)
|
||||
|
||||
album=$(gettag "$infos" album)
|
||||
|
||||
title=$(gettag "$infos" title)
|
||||
|
||||
tracknum=$(gettag "$infos" tracknumber)
|
||||
|
||||
tracktotal=$(gettag "$infos" tracktotal)
|
||||
|
||||
year=$(gettag "$infos" date)
|
||||
|
||||
disc=$(gettag "$infos" discnumber)
|
||||
|
||||
genre=$(gettag "$infos" genre)
|
||||
|
||||
unset infos
|
||||
}
|
||||
|
||||
function vorbis_info {
|
||||
infos=$(ionice -c3 ogginfo "$1" | sed 's/^\t//')
|
||||
|
||||
artist=$(gettag "$infos" artist)
|
||||
|
||||
album=$(gettag "$infos" album)
|
||||
|
||||
title=$(gettag "$infos" title)
|
||||
|
||||
tracknum=$(gettag "$infos" tracknumber)
|
||||
|
||||
tracktotal=$(gettag "$infos" tracktotal)
|
||||
|
||||
year=$(gettag "$infos" date)
|
||||
|
||||
disc=$(gettag "$infos" discnumber)
|
||||
|
||||
genre=$(gettag "$infos" genre)
|
||||
|
||||
unset infos
|
||||
}
|
||||
|
||||
function mp3_info {
|
||||
infos=$(ionice -c3 mp3info -p 'artist=%a
|
||||
album=%l
|
||||
title=%t
|
||||
tracknum=%n
|
||||
year=%y
|
||||
genre=%g' "$1" | iconv -f $ID3CHARSET -t utf-8//TRANSLIT)
|
||||
artist=$(gettag "$infos" artist|iconv -t utf-8)
|
||||
album=$(gettag "$infos" album|iconv -t utf-8)
|
||||
title=$(gettag "$infos" title|iconv -t utf-8)
|
||||
tracknum=$(gettag "$infos" tracknum|iconv -t utf-8)
|
||||
year=$(gettag "$infos" year)
|
||||
genre=$(gettag "$infos" genre)
|
||||
|
||||
unset infos
|
||||
}
|
||||
|
||||
function get_info {
|
||||
case "$(file "$1")" in
|
||||
*Musepack*)
|
||||
mpc_info "$1"
|
||||
;;
|
||||
*MPEG*)
|
||||
mp3_info "$1"
|
||||
;;
|
||||
*MP3*)
|
||||
mp3_info "$1"
|
||||
;;
|
||||
*Vorbis*)
|
||||
vorbis_info "$1"
|
||||
;;
|
||||
*FLAC*)
|
||||
flac_info "$1"
|
||||
;;
|
||||
*)
|
||||
:
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function theRealSox {
|
||||
echo "$1: $2 → $3" >&2
|
||||
get_info "$2" 2>/dev/null
|
||||
tmpfile="$TEMPDIR"/transogg-$UID-$(date +%Y%m%d%H%M%S%N).wav
|
||||
nice -n $NICENESS ionice -c3 \
|
||||
sox \
|
||||
--norm \
|
||||
--single-threaded "$2" \
|
||||
-r ${RATE:=44100} \
|
||||
-c ${CHANNELS:=2} \
|
||||
--temp $TEMPDIR \
|
||||
$tmpfile \
|
||||
> /dev/null || true
|
||||
encode "$2" "$3" || true
|
||||
rm -f $tmpfile
|
||||
unset artist album tracknum tracktotal title year genre tmpfile
|
||||
until echo $1 >> $IDFIFO
|
||||
do
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
function CleanIdFile {
|
||||
while read curid
|
||||
do
|
||||
if (( lastid + 1 == $curid ))
|
||||
then
|
||||
if [ -n "${files[$curid]}" ]
|
||||
then
|
||||
touch -r "$ORIGDIR/${files[$curid]}" "$TIMESTAMP"
|
||||
fi
|
||||
sed -n -i "/^$curid$/d;p" $IDFIFO
|
||||
lastid=$curid
|
||||
fi
|
||||
unset children[$curid]
|
||||
echo -n '' > $FIFO
|
||||
for processInd in ${!children[@]}
|
||||
do
|
||||
echo ${children[$processInd]} >> $FIFO
|
||||
done
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
done < <(sort -n $IDFIFO)
|
||||
}
|
||||
|
||||
function MySox {
|
||||
load=$(sed 's/^\([0-9]\+\)[. ].*/\1/' /proc/loadavg)
|
||||
if (( load > TARGETLOAD && instances > 1 && $(date +%s) - lastINSTchange >= LOADTIME))
|
||||
then
|
||||
((instances -= 1))
|
||||
if ((instances < 1))
|
||||
then
|
||||
instances=1
|
||||
fi
|
||||
lastINSTchange=$(date +%s)
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
elif (( load < TARGETLOAD && $(date +%s) - lastINSTchange >= LOADTIME))
|
||||
then
|
||||
((instances += 1))
|
||||
lastINSTchange=$(date +%s)
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
fi
|
||||
CleanIdFile
|
||||
until [ ${#children[@]} -lt $instances ]
|
||||
do
|
||||
load=$(sed 's/^\([0-9]\+\)[. ].*/\1/' /proc/loadavg)
|
||||
if (( load > TARGETLOAD && instances > 1 && $(date +%s) - lastINSTchange >= LOADTIME))
|
||||
then
|
||||
((instances -= 1))
|
||||
if ((instances < 1))
|
||||
then
|
||||
instances=1
|
||||
fi
|
||||
lastINSTchange=$(date +%s)
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
elif (( load < TARGETLOAD && $(date +%s) - lastINSTchange >= LOADTIME))
|
||||
then
|
||||
((instances += 1))
|
||||
lastINSTchange=$(date +%s)
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
fi
|
||||
CleanIdFile
|
||||
read -t 0.5 -n 1 load_change||true
|
||||
case $load_change in
|
||||
+) ((TARGETLOAD += 1))
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
;;
|
||||
-) ((TARGETLOAD -= 1))
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
;;
|
||||
q) cleanup
|
||||
message=Exiting...
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
;;
|
||||
esac
|
||||
if ((instances < 1))
|
||||
then
|
||||
instances=1
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
fi
|
||||
unset message
|
||||
done
|
||||
theRealSox $filenum "$1" "$2" 2>>$TEMPDIR/debug-$MyPID-theRealSox &
|
||||
children[$filenum]="${1#$ORIGDIR/}"
|
||||
}
|
||||
|
||||
function FileDisappeared {
|
||||
dialog --yes-label "Continue" \
|
||||
--no-label "Rescan" \
|
||||
--yesno "File $1 disappeared!" \
|
||||
$LINES $COLUMNS
|
||||
}
|
||||
|
||||
function FindFiles {
|
||||
cd "$ORIGDIR" || {
|
||||
echo "Could not cd into $ORIGDIR"
|
||||
exit 1
|
||||
}
|
||||
cd -
|
||||
readarray -t files < <(find "$ORIGDIR"/ \
|
||||
-newer "$TIMESTAMP" \
|
||||
-type f \
|
||||
-printf "%TY%Tm%Td%TH%TM.%TS %P\n" \
|
||||
| grep -v .timestamp \
|
||||
| tee >(dialog --output-fd 1 --progressbox "Looking for new files..." \
|
||||
$LINES $COLUMNS) \
|
||||
| sort \
|
||||
| sed 's/^[^ ]* //' )
|
||||
}
|
||||
|
||||
function ShowProgress {
|
||||
while read filenum concurrency targetload message
|
||||
do
|
||||
stamp=$(ls -go --time-style="+%d/%m/%Y %H:%M:%S" $TIMESTAMP | \
|
||||
awk '{print $4 " " $5}')
|
||||
if [ "$filenum" -gt 0 -a $nfiles -gt 0 ]
|
||||
then
|
||||
percent=$((${filenum:-${#files[@]}}*100/$nfiles))
|
||||
else
|
||||
percent=0
|
||||
fi
|
||||
echo XXX
|
||||
echo $percent
|
||||
echo "Position: ${filenum:-?} / $nfiles ($stamp) $message"
|
||||
echo "$concurrency processes max. Target load: $targetload."
|
||||
echo -e "(+/- to change, q to quit)\n"
|
||||
sed 's/$/\n/' $FIFO
|
||||
echo XXX
|
||||
done \
|
||||
| dialog \
|
||||
--title "Transcoding files from $ORIGDIR to $DESTDIR..." \
|
||||
--no-shadow \
|
||||
--gauge "Transcoding files from $ORIGDIR to $DESTDIR..." \
|
||||
$LINES $COLUMNS
|
||||
}
|
||||
|
||||
function ProcessFiles {
|
||||
lastINSTchange=$(date +%s)
|
||||
for filenum in ${!files[@]}
|
||||
do
|
||||
filename=${files[$filenum]}
|
||||
if [ -z "$filename" ]
|
||||
then
|
||||
break
|
||||
fi
|
||||
if [ ! -e "$ORIGDIR/$filename" ]
|
||||
then
|
||||
restart=1
|
||||
return 0
|
||||
fi
|
||||
destfile="$DESTDIR/${filename%.*}.$FORMAT"
|
||||
[ -d "${destfile%/?*}" ] || mkdir -p "${destfile%/?*}"
|
||||
MySox "$ORIGDIR/$filename" "$destfile"
|
||||
echo -n '' > $FIFO
|
||||
for processInd in ${!children[@]}
|
||||
do
|
||||
echo ${children[$processInd]} >> $FIFO
|
||||
done
|
||||
echo $filenum $instances $TARGETLOAD $message
|
||||
sleep 0.01
|
||||
done
|
||||
until [ ${#children[@]} -eq 0 ]
|
||||
do
|
||||
echo ${#files[@]} $instances $TARGETLOAD Finishing...
|
||||
sleep 1
|
||||
CleanIdFile
|
||||
done
|
||||
echo ${#files[@]} $instances $TARGETLOAD Done\!
|
||||
}
|
||||
|
||||
function Work {
|
||||
echo "Looking for new files..."
|
||||
FindFiles 2>$TEMPDIR/debug-$MyPID-FindFiles
|
||||
|
||||
nfiles=${#files[@]}
|
||||
|
||||
ProcessFiles 2>$TEMPDIR/debug-$MyPID-ProcessFiles \
|
||||
> >(ShowProgress 2>$TEMPDIR/debug-$MyPID-ShowProgress)
|
||||
sleep 1
|
||||
clear
|
||||
if [ -n "$killed" ]
|
||||
then
|
||||
rm $FIFO $IDFIFO
|
||||
exit 1
|
||||
fi
|
||||
while [ -n "$restart" ]
|
||||
do
|
||||
unset restart
|
||||
if FileDisappeared
|
||||
then
|
||||
for indice in {0..$lastid}
|
||||
do
|
||||
unset files[$indice]
|
||||
done
|
||||
ProcessFiles 2>>$TEMPDIR/debug-$MyPID-ProcessFiles \
|
||||
> >(ShowProgress 2>>$TEMPDIR/debug-$MyPID-ShowProgress)
|
||||
else
|
||||
Work
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
Work
|
||||
rm $FIFO $IDFIFO
|
||||
|
||||
set +x
|
||||
|
||||
clear
|
||||
|
||||
cd "$DESTDIR" || {
|
||||
echo "Could not cd into $DESTDIR"
|
||||
exit 1
|
||||
}
|
||||
(
|
||||
echo "Obsolete files..."
|
||||
find . -type f \
|
||||
| grep -v .timestamp \
|
||||
| grep -v 00-INDEX.txt \
|
||||
| while read filename
|
||||
do
|
||||
if [ ! -e "$ORIGDIR/${filename%.$FORMAT}".* ]
|
||||
then
|
||||
echo "Deleting $filename..."
|
||||
rm -f "$filename"
|
||||
fi
|
||||
done
|
||||
cd "$DESTDIR"
|
||||
cd "$OLDPWD"
|
||||
echo -e "\nEmpty directories..."
|
||||
find "$DESTDIR" -type d -empty -print -delete
|
||||
) | dialog --output-fd 1 --progressbox "Removing obsolete files..." $LINES $COLUMNS
|
||||
Loading…
x
Reference in New Issue
Block a user