747 lines
16 KiB
Bash
Executable File
747 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
## Define exit codes
|
|
# General config errors [10-19]
|
|
ELOAD=10
|
|
EINTERVAL=11
|
|
ENOCFG=19
|
|
# Source cofig errors [20-29]
|
|
# Destination config errors [30-49]
|
|
EFORMAT=30
|
|
ECHANNEL=31
|
|
EFMTINVPARM=49
|
|
|
|
# config structures
|
|
declare -A \
|
|
destinationchannels \
|
|
destinationfat32compat \
|
|
destinationcopymime \
|
|
destinationformat \
|
|
destinationfrequency \
|
|
destinationid \
|
|
destinationloss \
|
|
destinationmaxbps \
|
|
destinationnormalize \
|
|
destinationpath \
|
|
destinationquality \
|
|
destinationrename \
|
|
destinationnoresample \
|
|
destinationrenamepath \
|
|
destinationskipmime \
|
|
|| {
|
|
echo "Check your Bash version. You need >= 4.0" >&2
|
|
exit $EBASHVERS
|
|
}
|
|
|
|
declare -r \
|
|
DOCDIR=./doc \
|
|
LIBDIR=./lib \
|
|
SHAREDIR=./share
|
|
declare -r \
|
|
exampleconf=$DOCDIR/example.cfg \
|
|
schema=$SHAREDIR/schema.sql \
|
|
\
|
|
oldIFS="$IFS"
|
|
|
|
cffile="$HOME/.atom/atom.cfg"
|
|
|
|
LC_ALL=C
|
|
|
|
shopt -s extglob
|
|
|
|
source $SHAREDIR/id3genres
|
|
|
|
for function in "$LIBDIR"/*/*
|
|
do
|
|
source "$function"
|
|
done
|
|
|
|
#parse arguments
|
|
OPTERR=0
|
|
while getopts ':c:Cl:T:F:hD' opt
|
|
do
|
|
case $opt in
|
|
c)
|
|
cffile="$OPTARG"
|
|
;;
|
|
C)
|
|
cfgdump=1
|
|
;;
|
|
l)
|
|
cliload="$OPTARG"
|
|
;;
|
|
T)
|
|
cliltimer="$OPTARG"
|
|
;;
|
|
F)
|
|
forceall+=("$OPTARG")
|
|
;;
|
|
h)
|
|
help
|
|
exit 0
|
|
;;
|
|
D)
|
|
(( debug++ ))
|
|
;;
|
|
:)
|
|
echo "-$OPTARG requires an argument"
|
|
help
|
|
exit 127
|
|
;;
|
|
*)
|
|
echo "Unrecognized option: -$OPTARG"
|
|
help
|
|
exit 127
|
|
;;
|
|
esac
|
|
done
|
|
|
|
#FIXME: check sanity
|
|
|
|
if [ ! -f "$cffile" ]
|
|
then
|
|
if [ ! -d ~/.atom ]
|
|
then
|
|
mkdir -p ~/.atom
|
|
fi
|
|
sed "s:%HOME%:$HOME:" "$exampleconf" > "$cffile"
|
|
cat >&2 <<-EOCfgNotice
|
|
No configuration file found!
|
|
An example file has been created as "${cffile/$HOME/~}".
|
|
You should change it to your likings using you favorite editor.
|
|
|
|
Bailing out.
|
|
EOCfgNotice
|
|
exit $ENOCFG
|
|
fi
|
|
getConfig
|
|
|
|
set +H
|
|
(( debug || cfgdump )) && printConfig
|
|
(( cfgdump )) && exit
|
|
|
|
openDatabase
|
|
|
|
createDestinations
|
|
|
|
getFiles
|
|
|
|
updateMimes
|
|
|
|
removeObsoleteFiles
|
|
|
|
echo '
|
|
SELECT id,
|
|
filename
|
|
FROM destination_files
|
|
WHERE source_file_id is NULL;
|
|
|
|
SELECT "AtOM:NoMoreFiles";
|
|
' >&3
|
|
|
|
deleted=0
|
|
removed=0
|
|
read -u4 line
|
|
until [[ $line == AtOM:NoMoreFiles ]]
|
|
do
|
|
id=${line%::AtOM:SQL:Sep::*}
|
|
filename=${line#*::AtOM:SQL:Sep::}
|
|
if [ -n "$filename" ]
|
|
then
|
|
if rm -f "$filename"
|
|
then
|
|
Delete destination_files <<<"id = $id"
|
|
(( ++deleted ))
|
|
fi
|
|
else
|
|
Delete destination_files <<<"id = $id"
|
|
(( ++removed ))
|
|
fi
|
|
read -u4 line
|
|
done
|
|
echo "Suppressed $deleted files, $removed removed from database"
|
|
|
|
# get files
|
|
for reader in "${tagreaders[@]}"
|
|
do
|
|
tagreaderclause+="${tagreaderclause:+ AND }NOT tags.tagreader = \"$reader\""
|
|
done
|
|
echo '
|
|
SELECT COUNT(DISTINCT source_files.filename)
|
|
FROM source_files
|
|
INNER JOIN destination_files
|
|
ON destination_files.source_file_id=source_files.id
|
|
INNER JOIN destinations
|
|
ON destination_files.destination_id=destinations.id
|
|
INNER JOIN mime_type_actions
|
|
ON destinations.id=mime_type_actions.destination_id
|
|
INNER JOIN tags
|
|
ON source_files.id=tags.source_file
|
|
WHERE mime_type_actions.id = source_files.mime_type
|
|
AND (
|
|
CAST(tags.last_change AS TEXT)
|
|
<>
|
|
CAST(source_files.last_change AS TEXT)
|
|
OR ('"$tagreaderclause"')
|
|
)
|
|
AND mime_type_actions.action = 1;' >&3
|
|
read -u4 filecount
|
|
echo '
|
|
SELECT DISTINCT
|
|
source_files.id,
|
|
source_files.last_change,
|
|
mime_type_actions.mime_text,
|
|
source_files.filename
|
|
FROM source_files
|
|
INNER JOIN destination_files
|
|
ON destination_files.source_file_id=source_files.id
|
|
INNER JOIN destinations
|
|
ON destination_files.destination_id=destinations.id
|
|
INNER JOIN mime_type_actions
|
|
ON destinations.id=mime_type_actions.destination_id
|
|
INNER JOIN tags
|
|
ON source_files.id=tags.source_file
|
|
WHERE mime_type_actions.id = source_files.mime_type
|
|
AND (
|
|
CAST(tags.last_change AS TEXT)
|
|
<>
|
|
CAST(source_files.last_change AS TEXT)
|
|
OR ('"$tagreaderclause"')
|
|
)
|
|
AND mime_type_actions.action = 1;
|
|
|
|
SELECT "AtOM:NoMoreFiles";' >&3
|
|
read -u4 line
|
|
while ! [[ $line = AtOM:NoMoreFiles ]]
|
|
do
|
|
tagfiles+=("$line")
|
|
read -u4 line
|
|
done
|
|
echo 'BEGIN TRANSACTION;' >&3
|
|
for line in "${tagfiles[@]}"
|
|
do
|
|
sourcefileid=${line%%::AtOM:SQL:Sep::*}
|
|
rest=${line#*::AtOM:SQL:Sep::}
|
|
lastchange=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
mimetype=${rest%%::AtOM:SQL:Sep::*}
|
|
filename=${rest#*::AtOM:SQL:Sep::}
|
|
echo -en "\rTags: $((++count*100/filecount))%"
|
|
if (( count % 1000 == 0 ))
|
|
then
|
|
echo 'COMMIT;BEGIN TRANSACTION;' >&3
|
|
(( debug )) \
|
|
&& echo -n " $count files read, committing..."
|
|
fi
|
|
if getTags
|
|
then
|
|
Update tags \
|
|
album "${album:-NULL}" \
|
|
albumartist "${albumartist:-NULL}" \
|
|
artist "${artist:-NULL}" \
|
|
composer "${composer:-NULL}" \
|
|
disc "${disc:-NULL}" \
|
|
genre "${genre:-NULL}" \
|
|
performer "${performer:-NULL}" \
|
|
title "${title:-NULL}" \
|
|
track "${tracknum:-NULL}" \
|
|
year "${year:-NULL}" \
|
|
last_change "$lastchange" \
|
|
rate "${rate:-NULL}" \
|
|
channels "${channels:-NULL}" \
|
|
bitrate "${bitrate:-NULL}" \
|
|
tagreader "$tagreader" \
|
|
>/dev/null <<<"source_file = $sourcefileid"
|
|
unset genre \
|
|
albumartist \
|
|
year \
|
|
album \
|
|
disc \
|
|
artist \
|
|
tracknum \
|
|
title \
|
|
composer \
|
|
performer \
|
|
rate \
|
|
bitrate \
|
|
channels
|
|
fi
|
|
done
|
|
echo 'COMMIT;' >&3
|
|
echo -e "\rRead tags from ${count:-0} files.\033[K"
|
|
unset count tagfiles
|
|
|
|
echo '
|
|
CREATE TEMPORARY TABLE tasks(
|
|
id INTEGER PRIMARY KEY,
|
|
key TEXT UNIQUE,
|
|
rename_pattern TEXT,
|
|
source_file INTEGER,
|
|
fileid INTEGER,
|
|
filename TEXT,
|
|
cmd_arg0 TEXT,
|
|
cmd_arg1 TEXT,
|
|
cmd_arg2 TEXT,
|
|
cmd_arg3 TEXT,
|
|
cmd_arg4 TEXT,
|
|
cmd_arg5 TEXT,
|
|
cmd_arg6 TEXT,
|
|
cmd_arg7 TEXT,
|
|
cmd_arg8 TEXT,
|
|
cmd_arg9 TEXT,
|
|
cmd_arg10 TEXT,
|
|
cmd_arg11 TEXT,
|
|
cmd_arg12 TEXT,
|
|
cmd_arg13 TEXT,
|
|
cmd_arg14 TEXT,
|
|
cmd_arg15 TEXT,
|
|
cmd_arg16 TEXT,
|
|
cmd_arg17 TEXT,
|
|
cmd_arg18 TEXT,
|
|
cmd_arg19 TEXT,
|
|
cmd_arg20 TEXT,
|
|
cmd_arg21 TEXT,
|
|
cmd_arg22 TEXT,
|
|
cmd_arg23 TEXT,
|
|
cmd_arg24 TEXT,
|
|
cmd_arg25 TEXT,
|
|
cmd_arg26 TEXT,
|
|
cmd_arg27 TEXT,
|
|
cmd_arg28 TEXT,
|
|
cmd_arg29 TEXT,
|
|
requires INTEGER,
|
|
required INTEGER,
|
|
status INTEGER NOT NULL,
|
|
cleanup TEXT,
|
|
FOREIGN KEY(requires) REFERENCES tasks(id)
|
|
ON DELETE SET NULL
|
|
);
|
|
CREATE INDEX tasks_by_key ON tasks ( key );
|
|
CREATE INDEX tasks_by_sourcefile ON tasks ( source_file );
|
|
' >&3
|
|
|
|
echo '
|
|
SELECT COUNT(source_files.id)
|
|
FROM source_files
|
|
INNER JOIN destination_files
|
|
ON source_files.id
|
|
= destination_files.source_file_id
|
|
INNER JOIN destinations
|
|
ON destination_files.destination_id=destinations.id
|
|
INNER JOIN mime_type_actions
|
|
ON mime_type_actions.id = source_files.mime_type
|
|
INNER JOIN tags
|
|
ON source_files.id = tags.source_file
|
|
WHERE CAST(destination_files.last_change AS TEXT)
|
|
<> CAST(source_files.last_change AS TEXT)
|
|
AND mime_type_actions.destination_id = destinations.id
|
|
AND mime_type_actions.action = 1;' >&3
|
|
read -u4 filecount
|
|
echo '
|
|
SELECT
|
|
source_files.id,
|
|
source_files.filename,
|
|
mime_type_actions.mime_text,
|
|
destinations.name,
|
|
destination_files.id,
|
|
tags.rate,
|
|
tags.channels,
|
|
tags.bitrate,
|
|
tags.genre,
|
|
tags.albumartist,
|
|
tags.year,
|
|
tags.album,
|
|
tags.disc,
|
|
tags.artist,
|
|
tags.track,
|
|
tags.title,
|
|
tags.composer,
|
|
tags.performer
|
|
FROM source_files
|
|
INNER JOIN destination_files
|
|
ON source_files.id
|
|
= destination_files.source_file_id
|
|
INNER JOIN destinations
|
|
ON destination_files.destination_id=destinations.id
|
|
INNER JOIN mime_type_actions
|
|
ON mime_type_actions.id = source_files.mime_type
|
|
INNER JOIN tags
|
|
ON source_files.id = tags.source_file
|
|
WHERE CAST(destination_files.last_change AS TEXT)
|
|
<> CAST(source_files.last_change AS TEXT)
|
|
AND mime_type_actions.destination_id = destinations.id
|
|
AND mime_type_actions.action = 1;
|
|
|
|
SELECT "AtOM:NoMoreFiles";' >&3
|
|
read -u4 line
|
|
while ! [[ $line = AtOM:NoMoreFiles ]]
|
|
do
|
|
decodefiles+=("$line::AtOM:SQL:Sep::")
|
|
read -u4 line
|
|
done
|
|
echo -n 'Creating tasks... '
|
|
|
|
echo 'BEGIN TRANSACTION;' >&3
|
|
for line in "${decodefiles[@]}"
|
|
do
|
|
fileid=${line%%::AtOM:SQL:Sep::*}
|
|
rest=${line#*::AtOM:SQL:Sep::}
|
|
filename=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
mimetype=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
destination=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
destfileid=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
rate=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
channels=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
bitrate=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
genre=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
albumartist=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
year=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
album=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
disc=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
artist=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
track=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
title=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
composer=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
performer=${rest%%::AtOM:SQL:Sep::*}
|
|
unset rest
|
|
decodeFile
|
|
getDestDir
|
|
getDestFile
|
|
if (( copied ))
|
|
then
|
|
copyFiles_matching
|
|
else
|
|
encodeFile::${destinationformat[$destination]}
|
|
fi
|
|
unset \
|
|
album \
|
|
albumartist \
|
|
artist \
|
|
bitrate \
|
|
channels \
|
|
commandline \
|
|
composer \
|
|
copied \
|
|
decodetaskid \
|
|
destfileid \
|
|
destination \
|
|
disc \
|
|
fileid \
|
|
filename \
|
|
mimetype \
|
|
performer \
|
|
rate \
|
|
rest \
|
|
sox_needed \
|
|
soxoptions_in \
|
|
soxoptions_out \
|
|
soxtaskid \
|
|
title \
|
|
track \
|
|
year \
|
|
tmpfile
|
|
done
|
|
echo 'COMMIT;' >&3
|
|
echo -e "\rCreated ${count:-0} tasks for $filecount files (${copies:-0} immediate copies)"
|
|
|
|
concurrency=$(( maxload / 2 ))
|
|
(( concurrency )) || concurrency=1
|
|
active=0
|
|
concurrencychange=$(date +%s)
|
|
starttime=$concurrencychange
|
|
taskcount=$count
|
|
remaining=$taskcount
|
|
failed=0
|
|
while (( (remaining || ${#workers[@]}) && ! quit ))
|
|
do
|
|
if read -n 1 -t 0.1 userinput
|
|
then
|
|
case $userinput in
|
|
'+')
|
|
((maxload++))
|
|
;;
|
|
'-')
|
|
((--maxload)) || ((maxload=1))
|
|
;;
|
|
[qQ])
|
|
quit=1
|
|
;;
|
|
esac
|
|
fi
|
|
read humanload garbage < /proc/loadavg
|
|
load=${humanload%.*}
|
|
if [ -z "$quit" ] && (( $(date +%s)-concurrencychange >= loadinterval ))
|
|
then
|
|
if (( concurrency > 1 )) \
|
|
&& (( load > maxload ))
|
|
then
|
|
concurrencychange=$(date +%s)
|
|
(( --concurrency ))
|
|
elif (( load < maxload )) && (( active > concurrency - 1 ))
|
|
then
|
|
concurrencychange=$(date +%s)
|
|
(( ++concurrency ))
|
|
fi
|
|
fi
|
|
checkworkers
|
|
cleaner
|
|
master
|
|
if (( ran ))
|
|
then
|
|
currenttime=$(date +%s)
|
|
avgduration=$((
|
|
((currenttime - starttime) * 1000)
|
|
/
|
|
ran
|
|
))
|
|
secsremaining=$(( remaining * avgduration / 1000 ))
|
|
(( days =
|
|
secsremaining
|
|
/
|
|
( 24*60*60 )
|
|
)) || true
|
|
(( hours =
|
|
( secsremaining - ( days*24*60*60 ) )
|
|
/
|
|
( 60*60 )
|
|
)) || true
|
|
(( minutes =
|
|
( secsremaining - ( ( days*24 + hours ) *60*60 ) )
|
|
/
|
|
60
|
|
)) || true
|
|
(( seconds =
|
|
secsremaining
|
|
-
|
|
( ( ( ( days*24 + hours ) *60 ) + minutes ) *60 )
|
|
)) || true
|
|
avgduration=$(printf %04i $avgduration)
|
|
avgdsec=${avgduration:0:-3}
|
|
avgdmsec=${avgduration#$avgdsec}
|
|
fi
|
|
fmtload='L:%4.1f/%i'
|
|
fmtworkers='W:%i/%i'
|
|
fmtprogress="T:%${#taskcount}i/%i (F:%i) %3i%%"
|
|
fmttime='%2id %2ih%02im%02is (A:%4.1fs/task)'
|
|
eta="ETA:$(
|
|
date -d "${days:-0} days
|
|
${hours:-0} hours
|
|
${minutes:-0} minutes
|
|
${seconds:-0} seconds" \
|
|
+'%d/%m %H:%M:%S'
|
|
)"
|
|
printf \
|
|
"\r$fmtload $fmtworkers $fmtprogress $fmttime $eta\033[K"\
|
|
$humanload \
|
|
$maxload \
|
|
${active:-0} \
|
|
${concurrency:-0} \
|
|
${ran:-0} \
|
|
${taskcount:-0} \
|
|
${failed:-0} \
|
|
$(( ran * 100 / taskcount )) \
|
|
${days:-0} \
|
|
${hours:-0} \
|
|
${minutes:-0} \
|
|
${seconds:-0} \
|
|
${avgdsec:-0}.${avgdmsec:-0}
|
|
done
|
|
unset count
|
|
|
|
endtime=$(date +%s)
|
|
|
|
(( elapsedseconds = endtime - starttime ))
|
|
(( days =
|
|
elapsedseconds
|
|
/
|
|
( 24*60*60 )
|
|
)) || true
|
|
(( hours =
|
|
( elapsedseconds - ( days*24*60*60 ) )
|
|
/
|
|
( 60*60 )
|
|
)) || true
|
|
(( minutes =
|
|
( elapsedseconds - ( ( days*24 + hours ) *60*60 ) )
|
|
/
|
|
60
|
|
)) || true
|
|
(( seconds =
|
|
elapsedseconds
|
|
-
|
|
( ( ( ( days*24 + hours ) *60 ) + minutes ) *60 )
|
|
)) || true
|
|
|
|
echo -e "\rRan ${ran:=0} tasks, $failed of which failed, in $days" \
|
|
"days, $hours hours, $minutes minutes and $seconds seconds.\033[K"
|
|
|
|
if [ -n "$quit" ]
|
|
then
|
|
closeDatabase
|
|
exit
|
|
fi
|
|
|
|
#set -x
|
|
for destination in "${!destinationpath[@]}"
|
|
do
|
|
echo '
|
|
SELECT
|
|
destination_files.filename,
|
|
destination_files.id,
|
|
source_files.filename,
|
|
tags.album,
|
|
tags.albumartist,
|
|
tags.artist,
|
|
tags.composer,
|
|
tags.disc,
|
|
tags.genre,
|
|
tags.performer,
|
|
tags.title,
|
|
tags.track,
|
|
tags.year
|
|
FROM destination_files
|
|
INNER JOIN destinations
|
|
ON destination_files.destination_id
|
|
=destinations.id
|
|
INNER JOIN tags
|
|
ON destination_files.source_file_id
|
|
=tags.source_file
|
|
INNER JOIN source_files
|
|
ON destination_files.source_file_id
|
|
=source_files.id
|
|
WHERE destinations.name="'"$destination"'"
|
|
AND (destination_files.rename_pattern
|
|
!=
|
|
"'"${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}"'"
|
|
OR destination_files.rename_pattern is NULL)
|
|
AND destination_files.last_change > 0
|
|
;
|
|
|
|
SELECT "AtOM:NoMoreFiles";
|
|
' >&3
|
|
|
|
read -u4 line
|
|
if [[ $line != AtOM:NoMoreFiles ]]
|
|
then
|
|
case "${destinationformat[$destination]}" in
|
|
'mp3') extension=mp3 ;;
|
|
'opus') extension=opus ;;
|
|
'vorbis') extension=ogg ;;
|
|
esac
|
|
echo -n "$destination: rename pattern changed, renaming files... "
|
|
while [[ $line != AtOM:NoMoreFiles ]]
|
|
do
|
|
oldfilename=${line%%::AtOM:SQL:Sep::*}
|
|
rest=${line#*::AtOM:SQL:Sep::}'::AtOM:SQL:Sep::'
|
|
destfileid=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
filename=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
album=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
albumartist=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
artist=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
composer=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
disc=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
genre=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
performer=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
title=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
track=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
year=${rest%%::AtOM:SQL:Sep::*}
|
|
rest=${rest#*::AtOM:SQL:Sep::}
|
|
if [ -n "$oldfilename" -a -f "$oldfilename" ]
|
|
then
|
|
getDestDir
|
|
getDestFile
|
|
destfilename="$destdir/$destfile.$extension"
|
|
if [[ $oldfilename != $destfilename ]]
|
|
then
|
|
mv "$oldfilename" "$destfilename"
|
|
progressSpin
|
|
fi
|
|
echo "UPDATE destination_files" \
|
|
"SET filename=\"${destfilename//\"/\"\"}\"," \
|
|
" rename_pattern=" \
|
|
"\"${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}\"" \
|
|
"WHERE id=$destfileid;" \
|
|
>&3
|
|
fi
|
|
read -u4 line
|
|
done
|
|
echo -e $'\r'"$destination: Renamed ${count:-0} files\033[K"
|
|
fi
|
|
unset count
|
|
done
|
|
|
|
copyFiles_action
|
|
|
|
echo '
|
|
SELECT id,
|
|
filename,
|
|
old_filename
|
|
FROM destination_files
|
|
WHERE old_filename IS NOT NULL;
|
|
|
|
SELECT "AtOM:NoMoreFiles";
|
|
' >&3
|
|
|
|
echo -n 'Removing obsolete files... '
|
|
lines=()
|
|
read -u4 line
|
|
while [[ $line != AtOM:NoMoreFiles ]]
|
|
do
|
|
lines+=("$line")
|
|
read -u4 line
|
|
done
|
|
echo 'BEGIN TRANSACTION;' >&3
|
|
for line in "${lines[@]}"
|
|
do
|
|
id=${line%%::AtOM:SQL:Sep::*}
|
|
rest=${line#*::AtOM:SQL:Sep::}
|
|
filename=${rest%%::AtOM:SQL:Sep::*}
|
|
oldfilename=${rest#*::AtOM:SQL:Sep::}
|
|
if [[ $oldfilename != $filename ]] && [ -f "$oldfilename" ]
|
|
then
|
|
rm -f "$oldfilename"
|
|
fi
|
|
Update destination_files old_filename NULL <<<"id = $id"
|
|
(( count++ ))
|
|
printf '\b\b\b\b%3i%%' $(( (100 * count) / ${#lines[@]} ))
|
|
done
|
|
echo 'COMMIT;' >&3
|
|
echo -e "\rRemoved ${count:-0} obsolete files.\033[K"
|
|
|
|
echo "Purging empty directories."
|
|
for path in "${destinationpath[@]}"
|
|
do
|
|
find "$path" -type d -empty -delete
|
|
done
|
|
|
|
closeDatabase
|
|
|
|
# vim:set ts=8 sw=8:
|