Merge branch 'split'

This commit is contained in:
Vincent Riquer 2013-04-08 11:29:19 +02:00
commit d3c46516a8
52 changed files with 1806 additions and 1708 deletions

1730
atom

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,8 @@ Sections:
too quickly. Set this too high, and AtOM will not adapt quickly enough to too quickly. Set this too high, and AtOM will not adapt quickly enough to
load increase. In both cases, your hard drive will suffer. In my load increase. In both cases, your hard drive will suffer. In my
experience, 30 seconds is a good value. experience, 30 seconds is a good value.
* ionice <class> [niceness]: IO-hungry processes will be run with ionice class
<class> and niceness [niceness] (if applicable). See man ionice for details.
* temporary-directory <directory>: String. Name speaks for itself: this is * temporary-directory <directory>: String. Name speaks for itself: this is
where FIFOs (for communicating with sqlite) and temporary WAVE files will where FIFOs (for communicating with sqlite) and temporary WAVE files will
be created. Note that debug logs (if enabled) will go there too. be created. Note that debug logs (if enabled) will go there too.

View File

@ -1,4 +1,5 @@
[general] [general]
ionice 3
max-load 6 max-load 6
load-interval 30 load-interval 30
temporary-directory %HOME%/.atom/tmp temporary-directory %HOME%/.atom/tmp

28
lib/config/getConfig Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
getConfig() {
while read key value
do
case $key in
'#'*)
#comment
;;
'')
#empty line
;;
'[general]')
context=General
;;
'[source]')
context=Source
;;
\[*\])
context=Destination
destination="${key#[}"
destination="${destination%]}"
;;
*)
getConfig$context
;;
esac
done < "$cffile"
}

View File

@ -0,0 +1,171 @@
#!/bin/bash
getConfigDestination() {
case "$key" in
'path')
destinationpath["$destination"]="$value"
;;
'format')
case "$value" in
'mp3')
destinationformat["$destination"]=mp3
;;
'opus')
destinationformat["$destination"]=opus
;;
'vorbis')
destinationformat["$destination"]=vorbis
;;
*)
echo "Unsupported destination format: $value" >2&
exit $EFORMAT
;;
esac
;;
'quality')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid quality value: $value" >&2
exit $EQUALITY
fi
unset expr
case "${destinationformat["$destination"]}" in
'vorbis')
destinationquality["$destination"]="$value"
;;
*)
echo "Invalid parameter \"$key\" for format \"${destinationformat["$destination"]}\"" >&2
exit $EFMTINVPARM
;;
esac
;;
'normalize')
case $value in
'true'|'on'|'yes')
destinationnormalize["$destination"]=1
;;
'false'|'off'|'no')
destinationnormalize["$destination"]=0
;;
*)
echo "normalize takes values:" \
"'yes' ,'true' ,'on', 'no', 'false',"\
"'off'"
;;
esac
;;
'bitrate')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid bitrate value: $value" >&2
exit $EQUALITY
fi
unset expr
case "${destinationformat["$destination"]}" in
'opus')
destinationquality["$destination"]="$value"
;;
'mp3')
destinationquality["$destination"]="$value"
;;
*)
echo "$Invalid parameter \"$key\" for format \"${destinationformat["$destination"]}\"" >&2
exit $EFMTINVPARM
;;
esac
;;
'loss')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid loss value: $value" >&2
exit $EQUALITY
fi
unset expr
case "${destinationformat["$destination"]}" in
'opus')
destinationloss["$destination"]="$value"
;;
*)
echo "$Invalid parameter \"$key\" for format \"${destinationformat["$destination"]}\"" >&2
exit $EFMTINVPARM
;;
esac
;;
'channels')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid channel count: $value" >&2
exit $ECHANNEL
fi
unset expr
destinationchannels["$destination"]=$value
;;
'frequency')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid frequency value: $value" >&2
exit $ECHANNEL
fi
unset expr
destinationfrequency["$destination"]=$value
;;
'noresample')
case $value in
'true'|'on'|'yes')
destinationnoresample["$destination"]=1
;;
'false'|'off'|'no')
destinationnoresample["$destination"]=0
;;
*)
echo "noresample takes values:" \
"'yes' ,'true' ,'on', 'no', 'false',"\
"'off'"
;;
esac
;;
'rename')
case "$value" in
*/*)
destinationrenamepath["$destination"]="${value%/*}"
;;
esac
destinationrename["$destination"]="${value##*/}"
;;
'fat32compat')
case $value in
'true'|'on'|'yes')
destinationfat32compat["$destination"]=1
;;
'false'|'off'|'no')
destinationfat32compat["$destination"]=0
;;
*)
echo "fat32compat takes values:" \
"'yes' ,'true' ,'on', 'no', 'false',"\
"'off'"
;;
esac
;;
'skip_mime-type')
destinationskipmime[$destination]="${destinationskipmime[$destination]:+${destinationskipmime[$destination]}|}$value"
;;
'copy_mime-type')
destinationcopymime[$destination]="${destinationcopymime[$destination]:+${destinationcopymime[$destination]}|}$value"
;;
'higher-than')
expr='^[0-9]*$'
if ! [[ $value =~ $expr ]]
then
echo "Invalid higher-than bitrate value: $value" >&2
exit $EMAXBPS
fi
unset expr
destinationmaxbps[$destination]="$value"
;;
esac
}

View File

@ -0,0 +1,79 @@
#!/bin/bash
getConfigGeneral() {
case $key in
'max-load')
expr='^[0-9]*$'
if [[ $value =~ $expr ]]
then
maxload="$value"
else
echo "Invalid max-load value: $value" >&2
exit $ELOAD
fi
unset expr
;;
'load-interval')
expr='^[0-9]*$'
if [[ $value =~ $expr ]]
then
loadinterval="$value"
else
echo "Invalid load-interval value: $value" >&2
exit $EINTERVAL
fi
unset expr
;;
'ionice')
read class niceness <<<"$value"
case $class in
1)
# real-time class, only root can do that
if (( UID ))
then
echo "IO class 'realtime' is"\
"not available to unprivileged"\
"users" >&2
exit $EIONICE
fi
if [ -n "$niceness" ] \
&& (( niceness >= 0 && niceness <= 7 ))
then
ionice="ionice -c1 -n$niceness "
else
echo "Invalid IO priority"\
"'$niceness'" >&2
exit $EIONICE
fi
;;
2)
if [ -n "$niceness" ] \
&& (( niceness >= 0 && niceness <= 7 ))
then
ionice="ionice -c2 -n$niceness "
else
echo "Invalid IO priority"\
"'$niceness'" >&2
exit $EIONICE
fi
;;
3)
ionice="ionice -c3 "
;;
*)
echo "Invalid ionice parameters $value"\
>&2
exit $EIONICE
;;
esac
;;
'temporary-directory')
tempdir="$value"
;;
'database')
database="$value"
;;
debug)
(( value > debug )) && debug=$value
;;
esac
}

View File

@ -0,0 +1,11 @@
#!/bin/bash
getConfigSource() {
case "$key" in
'path')
sourcepath="$value"
;;
'skip')
skippeddirectories+=( "$value" )
;;
esac
}

54
lib/config/print Normal file
View File

@ -0,0 +1,54 @@
#!/bin/bash
printConfig() {
{
echo "General|Config file|$cffile"
[ -n "$ionice" ] && echo "|IO Nice|$ionice"
cat <<-EOF
|Load|$maxload
|Load Interval|$loadinterval
|Temp Dir|$tempdir
|Database|$database
|Debug|$debug
Source|Path|$sourcepath
EOF
for prune_expression in "${skippeddirectories[@]}"
do
(( printed )) \
&& echo -n '||' \
|| echo -n '|Skipped directories|'
echo "$prune_expression"
printed=1
done
unset printed
for destination in ${!destinationpath[@]}
do
cat <<-EOF
$destination|Path|${destinationpath["$destination"]}
|Format|${destinationformat["$destination"]}
|Quality|${destinationquality["$destination"]}
EOF
if [[ ${destinationformat["$destination"]} == opus ]]
then
echo "|Expected loss|${destinationloss["$destination"]}"
elif [[ ${destinationformat["$destination"]} == mp3 ]]
then
echo "|Prevent resampling|${destinationnoresample["$destination"]}"
fi
cat <<-EOF
|Normalize|${destinationnormalize["$destination"]}
|Channels|${destinationchannels["$destination"]}
|Frequency|${destinationfrequency["$destination"]}
|Higher than|${destinationmaxbps["$destination"]}
|Fat32 Compat.|${destinationfat32compat["$destination"]}
|Path Change|${destinationrenamepath["$destination"]}
|File Rename|${destinationrename["$destination"]}
EOF
[ -n "${destinationskipmime["$destination"]}" ] \
&& echo "|Skipped mime-types|${destinationskipmime["$destination"]//\|/
||}"
[ -n "${destinationmskipime["$destination"]}" ] \
&& echo "|Copied mime-types|${destinationcopymime["$destination"]//\|/
||}"
done
}|column -t -s'|' -n
}

19
lib/copy/checkCopy Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
checkCopy() {
(
[ -z "${destinationfrequency[$destination]}" ] \
|| (( ${rate:-0} == ${destinationfrequency[$destination]} ))
) && (
[ -z "${destinationchannels[$destination]}" ] \
|| (( ${channels:-0} == ${destinationchannels[$destination]} ))
) && (
(( ${bitrate:-1000} == ${destinationquality[$destination]} )) \
|| (
[ -n "${destinationmaxbps[$destination]}" ] \
|| ((
${bitrate:-1000}
<= ${destinationmaxbps[$destination]:-0}
))
)
)
}

74
lib/copy/copyFiles_action Normal file
View File

@ -0,0 +1,74 @@
#!/bin/bash
copyFiles_action() {
echo '
SELECT
source_files.filename,
source_files.last_change,
destinations.id,
destination_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
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 = 2;
SELECT "AtOM:NoMoreFiles";' >&3
read -u4 line
while ! [[ $line = AtOM:NoMoreFiles ]]
do
copyfiles+=("$line")
read -u4 line
done
for copyfile in "${copyfiles[@]}"
do
sourcefilename=${copyfile%%|*}
rest="${copyfile#*|}|"
lastchange=${rest%%|*}
rest=${rest#*|}
destinationid=${rest%%|*}
rest=${rest#*|}
destfileid=${rest%%|*}
rest=${rest#*|}
echo 'SELECT IFNULL( (
SELECT destination_files.filename
FROM destination_files
INNER JOIN source_files
ON destination_files.source_file_id=source_files.id
INNER JOIN mime_type_actions
ON
mime_type_actions.id=source_files.mime_type
INNER JOIN destinations
ON destinations.id=destination_files.destination_id
WHERE destinations.id = '$destinationid'
AND source_files.filename LIKE "'"${sourcefilename%/*}"'/%"
AND mime_type_actions.action = 1
LIMIT 1
),"AtOM:NotFound");
'>&3
read -u4 filename
if [[ $filename != AtOM:NotFound ]]
then
destdir=${filename%/*}
if cp -al "$sourcepath/$sourcefilename" "$destdir" 2>/dev/null\
|| cp -a "$sourcepath/$sourcefilename" "$destdir"
then
Update destination_files \
filename "$destdir/${sourcefilename##*/}"\
rename_pattern "${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}"\
<<-EOWhere
id = $destfileid
last_change = $lastchange
EOWhere
progressSpin
fi
fi
done
}

View File

@ -0,0 +1,29 @@
#!/bin/bash
copyFiles_matching() {
extension="${filename##*.}"
cp -al \
"$sourcepath/$filename" \
"$destdir/$destfile.$extension" \
2>/dev/null \
|| cp -a \
"$sourcepath/$filename" \
"$destdir/$destfile.$extension"
echo \
"UPDATE destination_files" \
"SET filename=\"${filename//\"/\"\"}\"," \
" last_change=(" \
" SELECT last_change" \
" FROM source_files" \
" WHERE id=$fileid" \
" )," \
" old_filename=(" \
" SELECT filename" \
" FROM destination_files" \
" WHERE id=$destfileid" \
" )," \
" rename_pattern=" \
"\"${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}\""\
"WHERE id=$destfileid;" \
>&3
(( ++copies ))
}

24
lib/database/Delete Normal file
View File

@ -0,0 +1,24 @@
#!/bin/bash
Delete() {
#Delete table < where_key where_operator where_value
# [where_key where_operator where_value
# […]]
local \
table="$1" \
key \
operator \
value \
where_statement \
results
while read key operator value
do
(( ${#where_statement} )) && where_statement+=( "AND" )
if [[ $value == NULL ]]
then
where_statement+=( "$key is NULL" )
else
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
fi
done
echo "DELETE from $table WHERE ${where_statement[@]};" >&3
}

38
lib/database/Insert Normal file
View File

@ -0,0 +1,38 @@
#!/bin/bash
Insert() {
#Insert table [no_id] < key value
# [key value
# […]]
local \
table="$1" \
no_id="${2:-0}" \
insert_keys \
insert_values \
results
while read key value
do
(( ${#insert_keys} )) && insert_keys+=","
insert_keys+='`'"$key"'`'
(( ${#insert_values} )) && insert_values+=","
case $value in
'NULL')
insert_values+="NULL"
;;
+([0-9])?(.+([0-9])))
insert_values+=$value
;;
*)
insert_values+='"'"${value//\"/\"\"}"'"'
;;
esac
done
echo "INSERT INTO $table" \
"( $insert_keys )" \
"VALUES" \
"( $insert_values );" >&3
(( no_id )) || {
echo 'SELECT LAST_INSERT_ROWID();' >&3
read -u 4 results
echo "$results"
}
}

View File

@ -0,0 +1,43 @@
#!/bin/bash
InsertIfUnset() {
#InsertIfUnset table [no_id] < key value \n key value
local \
table="$1" \
no_id="${2:-0}" \
column \
key \
keys \
results \
value \
values
while read key value
do
keys+=( "$key" )
values+=( "$value" )
done
if (( no_id ))
then
column="${keys[0]}"
else
column='id'
fi
if ! results=$(
Select "$table" "$column" < <(
for key in ${!keys[@]}
do
echo "${keys[$key]}" = "${values[$key]}"
done
)
)
then
results=$(
Insert "$table" < <(
for key in ${!keys[@]}
do
echo "${keys[$key]}" "${values[$key]}"
done
)
)
fi
echo "$results"
}

View File

@ -0,0 +1,67 @@
#!/bin/bash
InsertOrUpdate() {
#InsertOrUpdate table set_key set_value [set_key set_value […]] < where_key where_value
# [where_key where_value
# […]]
local \
table="$1" \
argument \
key \
keys \
set_keys \
set_values \
value \
values \
what \
results
shift
what=key
for argument
do
case $what in
key)
set_keys+=( "$argument" )
what=value
;;
value)
set_values+=( "$argument" )
what=key
;;
esac
done
while read key value
do
keys+=( "$key" )
values+=( "$value" )
done
if results=$(
Select "$table" ${keys[0]} < <(
for key in ${!keys[@]}
do
echo "${keys[$key]}" = "${values[$key]}"
done
)
)
then
Update "$table" "$@" < <(
for key in ${!keys[@]}
do
echo "${keys[$key]}" = "${values[$key]}"
done
)
else
results=$(
Insert "$table" < <(
for key in ${!set_keys[@]}
do
echo "${set_keys[$key]}" "${set_values[$key]}"
done
for key in ${!keys[@]}
do
echo "${keys[$key]}" "${values[$key]}"
done
)
)
fi
echo "$results"
}

36
lib/database/Select Normal file
View File

@ -0,0 +1,36 @@
#!/bin/bash
Select() {
#Select table [col1 [col2 [..]]] < WHERE_key WHERE_operator WHERE_value
# [WHERE_key WHERE_operator WHERE_value
# […]]
local \
table="$1" \
col \
columns \
operator \
results \
where_statement
shift
for col
do
(( ${#columns} )) && columns+=','
columns+="$col"
done
while read key operator value
do
(( ${#where_statement} )) && where_statement+=( "AND" )
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
done
echo "SELECT IFNULL(" \
"(SELECT $columns FROM $table" \
"WHERE ${where_statement[@]})" \
",'SQL::Select:not found'" \
");" >&3
read -u 4 results
if ! [[ $results == "SQL::Select:not found" ]]
then
echo "$results"
else
return 1
fi
}

63
lib/database/Update Normal file
View File

@ -0,0 +1,63 @@
#!/bin/bash
Update() {
#Update table set_key set_value [set_key set_value […]] < where_key where_operator where_value
# [where_key where_operator where_value
# […]]
local \
table="$1" \
key \
argument \
operator \
value \
set_statement \
where_keys \
where_values \
what \
where_statement \
results
shift
what=key
for argument
do
case $what in
key)
set_statement="${set_statement:+${set_statement},}\`$argument\`"
what=value
;;
value)
case $argument in
'NULL')
set_statement+=" = NULL"
;;
+([0-9])?(.+([0-9])))
set_statement+=" = $argument"
;;
*)
set_statement+=" = "'"'"${argument//\"/\"\"}"'"'
;;
esac
what=key
;;
esac
done
while read key operator value
do
(( ${#where_statement} )) && where_statement+=( "AND" )
case $value in
'NULL')
where_statement+=( "$key is NULL" )
;;
+([0-9.]))
where_statement+=( "$key $operator $value" )
;;
*)
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
;;
esac
done
echo "UPDATE '$table' SET" \
"$set_statement" \
"WHERE" \
"${where_statement[@]}" \
";" >&3
}

View File

@ -0,0 +1,10 @@
#!/bin/bash
closeDatabase() {
echo .quit >&3
(( debug )) && echo -n "Waiting for SQLite to terminate... "
wait
(( debug )) && echo OK
exec 3>&-
exec 4<&-
rm "$tempdir"/sqlite.{in,out}
}

28
lib/database/openDatabase Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
openDatabase() {
if [ ! -d "$tempdir" ]
then
mkdir -p "$tempdir"
fi
rm -f "$tempdir"/sqlite.{in,out}
mkfifo "$tempdir"/sqlite.{in,out}
if [ ! -f "$database" ]
then
if [ ! -d "${database%/*}" ]
then
mkdir -p "${database%/*}"
fi
sqlite3 "$database" < $schema
fi
sqlite3 -bail "$database" \
< "$tempdir/sqlite.in" \
> "$tempdir/sqlite.out" &
exec 3> "$tempdir"/sqlite.in
exec 4< "$tempdir"/sqlite.out
if (( debug > 2 ))
then
exec 5>&3
exec 3> >(tee -a $tempdir/debug.log >&5)
fi
echo 'PRAGMA foreign_keys = ON;' >&3
}

49
lib/decode/decodeFile Normal file
View File

@ -0,0 +1,49 @@
#!/bin/bash
decodeFile() {
if ! decodetaskid=$(
Select tasks id <<<"key = $tmpfile"
)
then
decodetaskid=$(
Insert tasks <<-EOInsert
key $tmpfile
source_file $fileid
$(
for key in ${!commandline[@]}
do
echo "cmd_arg$key ${commandline[key]}"
done
)
status 0
EOInsert
)
progressSpin
fi
if (( sox_needed ))
then
cleanup="$tempdir/$tmpfile"
decodeSox "$tempdir/$tmpfile.wav"
if ! soxtaskid=$(
Select tasks id <<<"key = $tmpfile"
)
then
soxtaskid=$(
Insert tasks <<-EOInsert
key $tmpfile
source_file $fileid
$(
for key in ${!commandline[@]}
do
echo "cmd_arg$key ${commandline[key]}"
done
)
requires $decodetaskid
required $decodetaskid
status 0
cleanup $cleanup
EOInsert
)
progressSpin
fi
fi
}

6
lib/decode/decodeMpcdec Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
decodeMpcdec() {
tmpfile="${fileid}mpcdec"
commandline=(${ionice}mpcdec)
commandline+=("$sourcepath/$filename" "$tempdir/$tmpfile.wav")
}

6
lib/decode/decodeOpusdec Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
decodeOpusdec() {
tmpfile="${fileid}opusdec"
commandline=(${ionice}opusdec)
commandline+=("$sourcepath/$filename" "$tempdir/$tmpfile.wav")
}

31
lib/decode/decodeSox Normal file
View File

@ -0,0 +1,31 @@
#!/bin/bash
decodeSox() {
commandline=(${ionice}sox --single-threaded --temp "$tempdir")
soxoptions_in=''
soxoptions_out=''
if (( ${destinationnormalize["$destination"]} ))
then
commandline+=(--norm)
soxoptions_in+=' --norm'
fi
if [ -n "$1" ]
then
commandline+=("$1")
else
commandline+=("$sourcepath/$filename")
fi
if [ -n "${destinationfrequency["$destination"]}" ] \
&& (( ${rate:-0} != ${destinationfrequency["$destination"]} ))
then
commandline+=(-r ${destinationfrequency["$destination"]})
soxoptions_out+=" -r ${destinationfrequency["$destination"]}"
fi
if [ -n "${destinationchannels["$destination"]}" ] \
&& (( ${channels:-0} != ${destinationchannels["$destination"]} ))
then
commandline+=(-c ${destinationchannels["$destination"]})
soxoptions_out+=" -c ${destinationchannels["$destination"]}"
fi
tmpfile="$fileid${soxoptions_in// /}${soxoptions_out// /}"
commandline+=("$tempdir/$tmpfile.wav")
}

View File

@ -0,0 +1,17 @@
#!/bin/bash
createDestinations() {
for destination in ${!destinationpath[@]}
do
if ! [ -d "${destinationpath["$destination"]}" ]
then
if ! mkdir -p "${destinationpath["$destination"]}"
then
echo "$destination: Could not create ${destinationpath["$destination"]}!"
exit $EINVDEST
fi
fi
destinationid["$destination"]=$(
InsertIfUnset destinations <<<"name $destination"
)
done
}

View File

@ -0,0 +1,32 @@
#!/bin/bash
updateMimes() {
Update mime_actions action 1 <<<"action != 1"
for destination in ${!destinationskipmime[@]}
do
IFS='|'
for mime_type in ${destinationskipmime["$destination"]}
do
IFS="$oldIFS"
Update mime_type_actions action 0 >/dev/null < <(
cat <<-EOWhere
destination_id = ${destinationid["$destination"]}
mime_text LIKE ${mime_type//\*/%}
EOWhere
)
done
done
for destination in ${!destinationcopymime[@]}
do
IFS='|'
for mime_type in ${destinationcopymime["$destination"]}
do
IFS="$oldIFS"
Update mime_type_actions action 2 >/dev/null < <(
cat <<-EOWhere
destination_id = ${destinationid["$destination"]}
mime_text LIKE ${mime_type//\*/%}
EOWhere
)
done
done
}

View File

@ -0,0 +1,64 @@
#!/bin/bash
encodeFile::mp3() {
lameopts=(${ionice}lame --quiet)
lameopts+=(-v --abr ${destinationquality[$destination]})
[ -n "$album" ] && lameopts+=(--tl "$album" )
[ -n "$artist" ] && lameopts+=(--ta "$artist")
[ -n "$genre" ] && lameopts+=(--tg "$genre")
[ -n "$title" ] && lameopts+=(--tt "$title")
[ -n "$track" ] && lameopts+=(--tn "$track")
[ -n "$year" ] && lameopts+=(--ty "$year")
if (( ${destinationnoresample[$destination]:-0} == 1 ))
then
# If 'rate' is not one of these value, it cannot be encoded to
# MP3, in which case we'd be better of letting lame decide which
# rate to use.
if [ -n "${destinationfrequency["$destination"]}" ]
then
case ${destinationfrequency["$destination"]} in
48000) lameopts+=(--resample 48) ;;
44100) lameopts+=(--resample 44.1) ;;
32000) lameopts+=(--resample 32) ;;
24000) lameopts+=(--resample 24) ;;
22050) lameopts+=(--resample 22.05) ;;
16000) lameopts+=(--resample 16) ;;
12000) lameopts+=(--resample 12) ;;
11025) lameopts+=(--resample 11.025) ;;
8000) lameopts+=(--resample 8) ;;
esac
else
case $rate in
48000) lameopts+=(--resample 48) ;;
44100) lameopts+=(--resample 44.1) ;;
32000) lameopts+=(--resample 32) ;;
24000) lameopts+=(--resample 24) ;;
22050) lameopts+=(--resample 22.05) ;;
16000) lameopts+=(--resample 16) ;;
12000) lameopts+=(--resample 12) ;;
11025) lameopts+=(--resample 11.025) ;;
8000) lameopts+=(--resample 8) ;;
esac
fi
fi
lameopts+=("$tempdir/$tmpfile.wav" "$destdir/$destfile.mp3")
encodetaskid=$(
Insert tasks <<-EOInsert
key ${fileid}lame$destination
requires ${soxtaskid:-$decodetaskid}
required ${soxtaskid:-$decodetaskid}
fileid $destfileid
filename $destdir/$destfile.mp3
$(
for key in ${!lameopts[@]}
do
echo "cmd_arg$key ${lameopts[key]}"
done
)
cleanup $tempdir/$tmpfile.wav
source_file $fileid
status 0
rename_pattern ${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}
EOInsert
)
progressSpin
}

View File

@ -0,0 +1,39 @@
#!/bin/bash
encodeFile::opus() {
opusencopts=(${ionice}opusenc --music --quiet)
opusencopts+=(--bitrate ${destinationquality[$destination]})
[ -n "${destinationloss["$destination"]}" ] \
&& opusencopts+=(--expect-loss "${destinationloss["$destination"]}")
[ -n "$albumartist" ] && opusencopts+=(--comment "ALBUMARTIST=$albumartist")
[ -n "$album" ] && opusencopts+=(--comment "ALBUM=$album")
[ -n "$artist" ] && opusencopts+=(--artist "$artist")
[ -n "$composer" ] && opusencopts+=(--comment "COMPOSER=$composer")
[ -n "$disc" ] && opusencopts+=(--comment "DISCNUMBER=$disc")
[ -n "$genre" ] && opusencopts+=(--comment "GENRE=$genre")
[ -n "$performer" ] && opusencopts+=(--comment "PERFORMER=$performer")
[ -n "$title" ] && opusencopts+=(--title "$title")
[ -n "$track" ] && opusencopts+=(--comment "TRACKNUMBER=${track%/*}")
[ -n "${track#*/}" ] && opusencopts+=(--comment "TRACKTOTAL=${track#*/}")
[ -n "$year" ] && opusencopts+=(--comment "DATE=$year")
opusencopts+=("$tempdir/$tmpfile.wav" "$destdir/$destfile.opus")
encodetaskid=$(
Insert tasks <<-EOInsert
key ${fileid}opusenc$destination
requires ${soxtaskid:-$decodetaskid}
required ${soxtaskid:-$decodetaskid}
fileid $destfileid
filename $destdir/$destfile.ogg
$(
for key in ${!opusencopts[@]}
do
echo "cmd_arg$key ${opusencopts[key]}"
done
)
cleanup $tempdir/$tmpfile.wav
source_file $fileid
status 0
rename_pattern ${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}
EOInsert
)
progressSpin
}

View File

@ -0,0 +1,35 @@
#!/bin/bash
encodeFile::vorbis() {
oggencopts=(${ionice}oggenc -Q -q ${destinationquality[$destination]})
[ -n "$albumartist" ] && oggencopts+=(-c "ALBUMARTIST=$albumartist")
[ -n "$album" ] && oggencopts+=(-l "$album")
[ -n "$artist" ] && oggencopts+=(-a "$artist")
[ -n "$composer" ] && oggencopts+=(-c "COMPOSER=$composer")
[ -n "$disc" ] && oggencopts+=(-c "DISCNUMBER=$disc")
[ -n "$genre" ] && oggencopts+=(-G "$genre")
[ -n "$performer" ] && oggencopts+=(-c "PERFORMER=$performer")
[ -n "$title" ] && oggencopts+=(-t "$title")
[ -n "$track" ] && oggencopts+=(-N "$track")
[ -n "$year" ] && oggencopts+=(-d "$year")
oggencopts+=(-o "$destdir/$destfile.ogg" "$tempdir/$tmpfile.wav")
encodetaskid=$(
Insert tasks <<-EOInsert
key ${fileid}oggenc$destination
requires ${soxtaskid:-$decodetaskid}
required ${soxtaskid:-$decodetaskid}
fileid $destfileid
filename $destdir/$destfile.ogg
$(
for key in ${!oggencopts[@]}
do
echo "cmd_arg$key ${oggencopts[key]}"
done
)
cleanup $tempdir/$tmpfile.wav
source_file $fileid
status 0
rename_pattern ${destinationrenamepath[$destination]}/${destinationrename[$destination]}:${destinationfat32compat["$destination"]}
EOInsert
)
progressSpin
}

35
lib/files/getDestDir Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
getDestDir() {
destdir="${destinationpath[$destination]}/"
if [ -n "${destinationrenamepath[$destination]}" ]
then
destdir+="${destinationrenamepath[$destination]//%\{album\}/$album}"
replace=$(sanitizeFile "$albumartist")
destdir="${destdir//%\{albumartist\}/$replace}"
replace=$(sanitizeFile "$artist")
destdir="${destdir//%\{artist\}/$replace}"
replace=$(sanitizeFile "$genre")
destdir="${destdir//%\{genre\}/$replace}"
replace=$(sanitizeFile "$title")
destdir="${destdir//%\{title\}/$replace}"
tracknumber="${track%/*}"
replace=$(sanitizeFile "$tracknumber")
destdir="${destdir//%\{track\}/$replace}"
replace=$(sanitizeFile "$year")
destdir="${destdir//%\{year\}/$replace}"
replace=$(sanitizeFile "$disc")
destdir="${destdir//%\{disc\}/$replace}"
else
destdir+=$(sanitizeFile "${filename%%/*}")
part=${filename#*/}
while [[ $part =~ / ]]
do
destdir+="/$(sanitizeFile "${part%%/*}")"
part=${part#*/}
done
fi
if ! [ -d "$destdir" ]
then
mkdir -p "$destdir"
fi
}

19
lib/files/getDestFile Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
getDestFile() {
if [ -n "${destinationrename[$destination]}" ]
then
destfile="${destinationrename[$destination]//%\{album\}/$album}"
destfile="${destfile//%\{albumartist\}/$albumartist}"
destfile="${destfile//%\{artist\}/$artist}"
destfile="${destfile//%\{genre\}/$genre}"
destfile="${destfile//%\{title\}/$title}"
tracknumber="${track%/*}"
destfile="${destfile//%\{track\}/$tracknumber}"
destfile="${destfile//%\{year\}/$year}"
destfile="${destfile//%\{disc\}/$disc}"
else
destfile="${filename##*/}"
destfile="${destfile%.*}"
fi
destfile=$(sanitizeFile "$destfile")
}

64
lib/files/getFiles Normal file
View File

@ -0,0 +1,64 @@
#!/bin/bash
getFiles() {
scantime=$(date +%s)
for prune_expression in "${skippeddirectories[@]}"
do
prunes+="-path $sourcepath$prune_expression -prune -o "
done
echo -n "Scanning $sourcepath... "
# We probably have thousands of files, don't waste time on disk writes
echo 'BEGIN TRANSACTION;' >&3
while read time size filename
do
if ! Select source_files id >/dev/null <<-EOWhere
filename = $filename
mime_type > 0
last_change = $time
EOWhere
then
mimetype=$(file -b --mime-type "$sourcepath/$filename")
if [[ $mimetype == application/ogg ]]
then
case "$(head -n1 "$sourcepath/$filename")" in
*'vorbis'*)
mimetype+=' vorbis'
;;
*'OpusHead'*)
mimetype+=' opus'
;;
esac
fi
mimetypeid=$(
InsertIfUnset mime_types <<-EOInsert
mime_text $mimetype
EOInsert
)
InsertOrUpdate source_files \
last_change $time \
size $size \
last_seen $scantime \
mime_type $mimetypeid \
>/dev/null \
<<-EOWhere
filename $filename
EOWhere
(( ++new ))
if (( new % 1000 == 0 ))
then
echo 'COMMIT;BEGIN TRANSACTION;' >&3
(( debug )) \
&& echo -ne "\bCommitted $count files... "
fi
else
Update source_files last_seen $scantime <<-EOWhere
filename = $filename
EOWhere
fi
progressSpin
done < <(
find "$sourcepath" $prunes -type f -printf "%T@ %s %P\n"
)
echo 'COMMIT;' >&3
echo -e "\r${count:-0} files found, ${new:=0} new or changed."
unset count
}

View File

@ -0,0 +1,6 @@
#!/bin/bash
removeObsoleteFiles() {
Delete source_files <<-EOWhere
last_seen < $scantime
EOWhere
}

24
lib/files/sanitizeFile Normal file
View File

@ -0,0 +1,24 @@
#!/bin/bash
sanitizeFile() {
shopt -s extglob
string="$1"
# Filenames can't contain /
string="${string//\// }"
if (( ${destinationfat32compat[$destination]} ))
then
# Filenames can't contain:
string=${string//\?/ }
string=${string//\\/ }
string=${string//</ }
string=${string//>/ }
string=${string//:/ }
string=${string//\*/ }
string=${string//|/ }
string=${string//\"/ }
# Filenames can't begin or end with ' '
string=${string/#+( )/}
string=${string/%+( )/}
fi
echo "$string"
}

55
lib/tags/getInfos::APE Normal file
View File

@ -0,0 +1,55 @@
#!/bin/bash
getInfosAPE_version='APE-1'
tagreaders+=( "$getInfosAPE_version" )
getInfos::APE() {
# I was not able to find a decent cli tool to read APE tags.
# This is raw but works for the very few MusePack files I got.
#
# Please tell me if you know of any good tool.
tagreader="$getInfosAPE_version"
IFS='='
while read tag value
do
IFS="$oldIFS"
case $tag in
[Aa][Ll][Bb][Uu][Mm]' '[Aa][Rr][Tt][Ii][Ss][Tt])
albumartist="$value"
;;
[Aa][Rr][Tt][Ii][Ss][Tt])
artist="$value"
;;
[Yy][Ee][Aa][Rr])
year="$value"
;;
[Aa][Ll][Bb][Uu][Mm])
album="$value"
;;
[Tt][Ii][Tt][Ll][Ee])
title="$value"
;;
[Tt][Rr][Aa][Cc][Kk])
tracknum="$value"
;;
[Gg][Ee][Nn][Rr][Ee])
genre="$value"
;;
[Cc][Oo][Mm][Pp][Oo][Ss][Ee][Rr])
composer="$value"
;;
[Pp][Ee][Rr][Ff][Oo][Rr][Mm][Ee][Rr])
performer="$value"
;;
*)
;;
esac
IFS='='
done < <(
IFS="$oldIFS"
sed \
's/APETAGEX/\n/;s/[\x00\-\x1F]\x00\+/\n/g;s/\x00/=/g' \
"$sourcepath/$filename" \
| egrep -i \
'^(Album Artist|Artist|Year|Album|Title|Track|Genre|Composer|Performer)='
)
IFS="$oldIFS"
}

45
lib/tags/getInfos::FLAC Normal file
View File

@ -0,0 +1,45 @@
#!/bin/bash
getInfosFLAC_version='FLAC-1'
tagreaders+=( "$getInfosFLAC_version" )
getInfos::FLAC() {
tagreader="$getInfosFLAC_version"
infos=$(
metaflac \
--show-tag=ALBUM \
--show-tag=ALBUMARTIST \
--show-tag=ARTIST \
--show-tag=COMPOSER \
--show-tag=DATE \
--show-tag=DISCNUMBER \
--show-tag=GENRE \
--show-tag=PERFORMER \
--show-tag=TITLE \
--show-tag=TRACKNUMBER \
--show-tag=TRACKTOTAL \
"$sourcepath/$filename"
)
albumartist=$(gettag albumartist)
album=$(gettag album)
artist=$(gettag artist)
composer=$(gettag composer)
disc=$(gettag discnumber)
genre=$(gettag genre)
performer=$(gettag performer)
title=$(gettag title)
tracknum="$(gettag tracknumber)/$(gettag tracktotal)"
year=$(gettag date)
if [ -n "$tracknum" -a -n "$tracktotal" ]
then
tracknum="$tracknum/$tracktotal"
fi
year=$(gettag DATE)
{
read rate
read channels
} < <(
metaflac \
--show-sample-rate \
--show-channels \
"$sourcepath/$filename"
)
}

29
lib/tags/getInfos::MP3 Normal file
View File

@ -0,0 +1,29 @@
#!/bin/bash
getInfosMP3_version='ID3-2'
tagreaders+=( "$getInfosMP3_version" )
getInfos::MP3() {
tagreader="$getInfosMP3_version"
infos=$(
soxi "$sourcepath/$filename" 2>/dev/null \
| sed 's/ *: /=/'
)
album=$(gettag album)
artist=$(gettag artist)
genre=$(gettag genre)
title=$(gettag title)
tracknum=$(gettag tracknumber)
year=$(gettag year)
expr='^\([0-9]*\)$'
if [[ $genre =~ $expr ]]
then
genre=${genre%)}
genre=${genre#(}
genre="${id3genres[$genre]}"
fi
infos="${infos/: /=}"
channels=$(gettag channels)
rate=$(gettag 'sample rate')
bitrate=$(gettag 'bit rate')
bitrate=${bitrate%%.*}
bitrate=${bitrate%k}
}

30
lib/tags/getInfos::Ogg Normal file
View File

@ -0,0 +1,30 @@
#!/bin/bash
getInfosOgg_version='Ogg-1'
tagreaders+=( "$getInfosOgg_version" )
getInfos::Ogg() {
tagreader="$getInfosOgg_version"
infos=$(
ogginfo "$sourcepath/$filename" \
| sed 's/\t//'
)
albumartist=$(gettag albumartist)
album=$(gettag album)
artist=$(gettag artist)
composer=$(gettag composer)
disc=$(gettag discnumber)
genre=$(gettag genre)
performer=$(gettag performer)
title=$(gettag title)
tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal)
if [ -n "$tracknum" -a -n "$tracktotal" ]
then
tracknum="$tracknum/$tracktotal"
fi
year=$(gettag date)
infos="${infos/: /=}"
rate=$(gettag rate|head -n1)
channels=$(gettag channels|head -n1)
bitrate=$(gettag 'nominal bitrate')
bitrate=${bitrate%%,*}
}

30
lib/tags/getInfos::Opus Normal file
View File

@ -0,0 +1,30 @@
#!/bin/bash
getInfosOpus_version='Opus-1'
tagreaders+=( "$getInfosOpus_version" )
getInfos::Opus() {
tagreader="$getInfosOpus_version"
infos=$(
opusinfo "$sourcepath/$filename" \
| sed 's/\t//'
)
albumartist=$(gettag albumartist)
album=$(gettag album)
artist=$(gettag artist)
composer=$(gettag composer)
disc=$(gettag discnumber)
genre=$(gettag genre)
performer=$(gettag performer)
title=$(gettag title)
tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal)
if [ -n "$tracknum" -a -n "$tracktotal" ]
then
tracknum="$tracknum/$tracktotal"
fi
year=$(gettag date)
infos="${infos/: /=}"
rate=$(gettag 'original sample rate'|head -n1)
channels=$(gettag channels|head -n1)
bitrate=$(gettag 'average bitrate')
bitrate=${bitrate%%.*}
}

View File

@ -0,0 +1,16 @@
#!/bin/bash
getRateChannelMPC() {
while read key value garbage
do
case $key in
'samplerate:')
rate=$value
;;
'channels:')
channels=$value
;;
esac
done < <(
mpcdec "$sourcepath/$filename" -i 2>&1
)
}

View File

@ -0,0 +1,5 @@
#!/bin/bash
getRateChannelSoxi() {
rate=$(soxi -r "$sourcepath/$filename" 2>/dev/null)
channels=$(soxi -c "$sourcepath/$filename" 2>/dev/null)
}

42
lib/tags/getTags Normal file
View File

@ -0,0 +1,42 @@
#!/bin/bash
getTags_version='unknown-2'
tagreaders+=( "$getTags_version" )
getTags() {
unset type
case "$mimetype" in
audio/mpeg)
type=MP3
;;
'application/ogg opus')
type=Opus
;;
application/ogg*)
type=Ogg
;;
audio/x-flac)
type=FLAC
;;
*)
extendedtype=$(file -b "$sourcepath/$filename")
case "$extendedtype" in
*' ID3 '*)
type=MP3
;;
*'Musepack '*)
getRateChannelMPC
tryAPE
;;
*)
getRateChannelSoxi
tryAPE
;;
esac
;;
esac
if [ -n "$type" ]
then
getInfos::$type
else
tagreader=$getTags_version
fi
}

5
lib/tags/gettag Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
gettag() {
echo -e "$infos" \
| sed -n "/^${1}=/I{s/^${1}=//I;p;q}"
}

6
lib/tags/tryAPE Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
tryAPE() {
grep -q 'APETAGEX' \
"$sourcepath/$filename" \
&& type=APE
}

27
lib/tasks/gettaskinfos Normal file
View File

@ -0,0 +1,27 @@
#!/bin/bash
gettaskinfos() {
echo '
SELECT
id,
source_file,
required,
cleanup,
fileid,
filename
FROM tasks
WHERE id='$1';
' >&3
read -u4 line
taskid=${line%%|*}
rest="${line#*|}|"
sourcefileid=${rest%%|*}
rest=${rest#*|}
required=${rest%%|*}
rest=${rest#*|}
cleanup=${rest%%|*}
rest=${rest#*|}
destfileid=${rest%%|*}
rest=${rest#*|}
destfilename=${rest%%|*}
rest=${rest#*|}
}

10
lib/tools/progressSpin Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
progressSpin() {
case $(( ++count % 40 )) in
0) echo -ne '\b|' ;;
10) echo -ne '\b/' ;;
20) echo -en '\b-' ;;
30) echo -ne '\b\\' ;;
*) ;;
esac
}

20
lib/workers/checkworkers Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
checkworkers() {
for key in ${!workers[@]}
do
if ! kill -0 ${workers[key]} 2>/dev/null
then
taskid=${workertasks[key]}
(( ++ran ))
(( active-- ))
if destroyworker $key
then
finishedtasks+=($taskid)
else
failedtasks+=($taskid)
(( ++failed ))
fi
unset workertasks[key]
fi
done
}

65
lib/workers/cleaner Normal file
View File

@ -0,0 +1,65 @@
#!/bin/bash
cleaner() {
for key in ${!failedtasks[@]}
do
taskid=${failedtasks[key]}
gettaskinfos $taskid
faildepends=$(
Select tasks 'COUNT(*)' <<-EOWhere
requires = $taskid
EOWhere
)
(( failed+=faildepends ))
Update tasks status 2 <<<"id = $taskid"
Update tasks status 2 <<<"requires = $taskid"
echo "SELECT COUNT(*)
FROM tasks
WHERE ( status = 0 OR status = 1 )
AND required = $taskid;">&3
read -u4 count
if (( count == 0 ))
then
rm -f "$cleanup"
fi
unset failedtasks[key]
done
for key in ${!finishedtasks[@]}
do
taskid=${finishedtasks[key]}
gettaskinfos $taskid
if [ -n "$destfilename" ]
then
echo \
"UPDATE destination_files" \
"SET filename=\"${destfilename//\"/\"\"}\"," \
" last_change=(" \
" SELECT last_change" \
" FROM source_files" \
" WHERE id=$sourcefileid" \
" )," \
" old_filename=(" \
" SELECT filename" \
" FROM destination_files" \
" WHERE id=$destfileid" \
" )," \
" rename_pattern=(" \
" SELECT rename_pattern" \
" FROM tasks" \
" WHERE id=$taskid" \
" )" \
"WHERE id=$destfileid;" \
>&3
fi
echo "SELECT COUNT(*)
FROM tasks
WHERE ( status = 0 OR status = 1 )
AND required = $taskid;">&3
read -u4 count
if (( count == 0 ))
then
rm -f "$cleanup"
fi
Delete tasks <<<"id = $taskid"
unset finishedtasks[key]
done
}

5
lib/workers/createworker Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
createworker() {
worker $1 &
workers[$1]=$!
}

View File

@ -0,0 +1,6 @@
#!/bin/bash
destroyworker() {
dyingworker=${workers[$1]}
unset workers[$1]
wait $dyingworker
}

15
lib/workers/getworkerid Normal file
View File

@ -0,0 +1,15 @@
#!/bin/bash
getworkerid() {
local i
for (( i=0 ; i >= 0 ; i++ ))
do
if [ -z "${workers[i]}" ]
then
echo $i
return
fi
done
# If we reach this, we have reached the signed long limit
# (2^63 - 1 = 9223372036854775807 - Got a supercomputer?)
(( concurrency-- ))
}

154
lib/workers/master Normal file
View File

@ -0,0 +1,154 @@
#!/bin/bash
master() {
if (( active >= concurrency)) || [ -n "$quit" ]
then
sleep 0.1
else
echo '
SELECT COUNT(*)
FROM tasks
WHERE status = 0;
SELECT COUNT(*)
FROM tasks
WHERE status = 0
AND requires is NULL;
SELECT
id,
source_file,
required,
cmd_arg0,
cmd_arg1,
cmd_arg2,
cmd_arg3,
cmd_arg4,
cmd_arg5,
cmd_arg6,
cmd_arg7,
cmd_arg8,
cmd_arg9,
cmd_arg10,
cmd_arg11,
cmd_arg12,
cmd_arg13,
cmd_arg14,
cmd_arg15,
cmd_arg16,
cmd_arg17,
cmd_arg18,
cmd_arg19,
cmd_arg20,
cmd_arg21,
cmd_arg22,
cmd_arg23,
cmd_arg24,
cmd_arg25,
cmd_arg26,
cmd_arg27,
cmd_arg28,
cmd_arg29,
cleanup,
fileid,
filename
FROM tasks
WHERE status = 0
AND requires is NULL
ORDER BY source_file
LIMIT 1;
' >&3
read -u4 remaining
read -u4 ready
if (( remaining == 0 ))
then
sleep 0.1
continue
elif (( ready == 0 ))
then
sleep 0.1
else
(( ++active ))
read -u4 line
taskid=${line%%|*}
rest="${line#*|}|"
sourcefileid=${rest%%|*}
rest=${rest#*|}
required=${rest%%|*}
rest=${rest#*|}
cmd_arg=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cmd_arg+=("${rest%%|*}")
rest=${rest#*|}
cleanup=${rest%%|*}
rest=${rest#*|}
destfileid=${rest%%|*}
rest=${rest#*|}
destfilename=${rest%%|*}
rest=${rest#*|}
for key in ${!cmd_arg[@]}
do
[ -z "${cmd_arg[key]}" ] && unset cmd_arg[key]
done
workerid=$(getworkerid)
workertasks[workerid]=$taskid
Update tasks status 1 <<<"id = $taskid"
createworker $workerid
fi
fi
}

15
lib/workers/worker Normal file
View File

@ -0,0 +1,15 @@
#!/bin/bash
worker() {
exec 2>>"$tempdir/worker$1.log"
(( debug >= 2 )) && echo "${cmd_arg[@]}" >&2
"${cmd_arg[@]}" >/dev/null
}
createworker() {
worker $1 &
workers[$1]=$!
}
destroyworker() {
dyingworker=${workers[$1]}
unset workers[$1]
wait $dyingworker
}