Compare commits

..

1 Commits

Author SHA1 Message Date
Vincent Riquer
05c64976db Everybody gets a sanityCheck 2025-03-13 02:19:14 +01:00
33 changed files with 467 additions and 790 deletions

View File

@ -1,31 +1,16 @@
# 1.0.3
## `BREAKING CHANGES`
* Implementing replaygain copy meant bumping versions of every tag parser. All file tags will be read again. Running in batches (`-B <batchsize>`) is recommended.
### Bugs
* Fix a number of issues with `releasecountry` tag
### Enhancements
* Spawn tasks faster when slots are available.
* Copy replaygain tags.
* Add `copy_extension` to setup
# 1.0.2 # 1.0.2
### Bugs ## Bugs
* Tag reading hangs on vorbis files with embedded images. * Tag reading hangs on vorbis files with embedded images
* Recreate destination files on releasecountry tag change (bump database schema to 5). * Recreate destination files on releasecountry tag change (bump database schema to 5)
# 1.0.1 # 1.0.1
## `BREAKING CHANGES` ## BREAKING CHANGES
* Implementing releasecountry meant bumping versions of every tag parser. All file tags will be read again. Running in batches (`-B <batchsize>`) is recommended. Implementing releasecountry meant bumping versions of every tag parser. All file tags will be read again. Running in batches (`-B <batchsize>`) is recommended.
### Enhancements ## Bugs
* Copy releasecountry tag ("MusicBrainz Album Release Country" for MP3). Opus tags were not actually parsed due to an issue with the tag reader selector.
### Bugs ## Enhancements
* Opus tags were not actually parsed due to an issue with the tag reader selector.
### Enhancements
* Fetch releasecountry tag from files * Fetch releasecountry tag from files
* Add `%{releasecountry}` placeholder in `rename` * Add `%{releasecountry}` placeholder in `rename`
* Add `-r` (show release country) to toys/createindex * Add `-r` (show release country) to toys/createindex

View File

@ -20,17 +20,17 @@ in the same format, it will want a constant sample-rate and bitrate. You can
have AtOM do that! have AtOM do that!
Here's what I have for my tests: Here's what I have for my tests:
| Directory | Format | Sample rate | Bitrate | Channels | FAT32 compat. | ASCII | Size | | Directory | Format | Frequency | Bitrate | Channels | FAT32 compat. | ASCII | Size |
| --------- | ------ | ----------- | ------- | -------- | ------------- | ----- | ---- | | --------- | ------ | --------- | ------- | -------- | ------------- | ----- | ---- |
| 0-Full | Mixed | Mixed | Mixed | Mixed | No | No | 508G | | 0-Full | Mixed | Mixed | Mixed | Mixed | No | No | 508G |
| 1-High | Opus | Same | 128 | Same | Yes | No | 101G | | 1-High | Opus | Same | 128 | Same | Yes | No | 101G |
| 2-Medium | Opus | Same | 64 | Same | Yes | No | 59G | | 2-Medium | Opus | Same | 64 | Same | Yes | No | 59G |
| 3-Small | Opus | Same | 32 | Same | Yes | No | 30G | | 3-Small | Opus | Same | 32 | Same | Yes | No | 30G |
| 4-MP3 | MP3 | 44100 | 128 | 2 | Yes | Yes | 114G | | 4-MP3 | MP3 | 44100 | 128 | 2 | Yes | Yes | 114G |
* URL: https://framagit.org/atom/AtOM/ * URL: https://framagit.org/ScriptFanix/AtOM/
* Author: Vincent Riquer <vincent+prog.atom@riquer.fr> * Author: Vincent Riquer <vincent+prog.atom@riquer.fr>
* Copyright/left: 2012-2013,2015,2025 Vincent Riquer - GPLv3 * Copyright/left: 2012-2013,2015,2025 Vincent Riquer - GPLv3

5
TODO Normal file
View File

@ -0,0 +1,5 @@
Tag Guessing
------------
From a user-defined pattern, guess tags for unsupported formats/untagged files
from the file path and file name.

85
atom
View File

@ -398,23 +398,20 @@ echo '
mime_type_actions.mime_text, mime_type_actions.mime_text,
destinations.name, destinations.name,
destination_files.id, destination_files.id,
tags.album,
tags.albumartist,
tags.artist,
tags.bitrate,
tags.channels,
tags.composer,
tags.depth, tags.depth,
tags.disc,
tags.genre,
tags.performer,
tags.rate, tags.rate,
tags.releasecountry, tags.channels,
tags.replaygain_alb, tags.bitrate,
tags.replaygain_trk, tags.genre,
tags.title, tags.albumartist,
tags.year,
tags.album,
tags.disc,
tags.artist,
tags.track, tags.track,
tags.year tags.title,
tags.composer,
tags.performer
FROM source_files FROM source_files
INNER JOIN destination_files INNER JOIN destination_files
ON source_files.id ON source_files.id
@ -457,39 +454,33 @@ do
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
destfileid=${rest%%::AtOM:SQL:Sep::*} destfileid=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
album=${rest%%::AtOM:SQL:Sep::*} bitdepth=${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::}
bitrate=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
channels=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
composer=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
depth=${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::} rest=${rest#*::AtOM:SQL:Sep::}
rate=${rest%%::AtOM:SQL:Sep::*} rate=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
releasecountry=${rest%%::AtOM:SQL:Sep::*} channels=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
replaygain_alb=${rest%%::AtOM:SQL:Sep::*} bitrate=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
replaygain_trk=${rest%%::AtOM:SQL:Sep::*} genre=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
title=${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::} rest=${rest#*::AtOM:SQL:Sep::}
track=${rest%%::AtOM:SQL:Sep::*} track=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
year=${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 unset rest
case ${destinationformat["$destination"]} in case ${destinationformat["$destination"]} in
vorbis) (( disableoggenc )) && continue ;; vorbis) (( disableoggenc )) && continue ;;
@ -501,7 +492,7 @@ do
getDestFile getDestFile
for copy_ext in "${destinationcopyext[@]}" for copy_ext in "${destinationcopyext[@]}"
do do
if [[ $filename =~ '.*\.'"$copy_ext"'$' ]] if [[ $filename =~ '.*'"$copy_ext" ]]
then then
copied=1 copied=1
break break
@ -517,13 +508,13 @@ do
album \ album \
albumartist \ albumartist \
artist \ artist \
bitdepth \
bitrate \ bitrate \
channels \ channels \
commandline \ commandline \
composer \ composer \
copied \ copied \
decodetaskid \ decodetaskid \
depth \
destfileid \ destfileid \
destination \ destination \
disc \ disc \
@ -532,9 +523,6 @@ do
mimetype \ mimetype \
performer \ performer \
rate \ rate \
releasecountry \
replaygain_alb \
replaygain_trk \
rest \ rest \
sox_needed \ sox_needed \
soxoptions_in \ soxoptions_in \
@ -555,16 +543,16 @@ echo "Created ${count:-0} tasks for $filecount files ${togo:+($togo left) }(${co
concurrency=$(( maxload / 2 )) concurrency=$(( maxload / 2 ))
(( concurrency )) || concurrency=1 (( concurrency )) || concurrency=1
active=0 active=0
concurrencychange=$EPOCHSECONDS concurrencychange=$(date +%s)
starttime=$concurrencychange starttime=$concurrencychange
taskcount=$count taskcount=$count
remaining=$taskcount remaining=$taskcount
failed=0 failed=0
echo 'BEGIN TRANSACTION;' >&3 echo 'BEGIN TRANSACTION;' >&3
committime=$EPOCHSECONDS committime=$(date +%s)
while (( (remaining || ${#workers[@]}) && ! quit )) while (( (remaining || ${#workers[@]}) && ! quit ))
do do
timestamp=$EPOCHSECONDS timestamp=$(date +%s)
if (( $timestamp - committime >= 60 )) if (( $timestamp - committime >= 60 ))
then then
echo $'COMMIT;\nBEGIN TRANSACTION;' >&3 echo $'COMMIT;\nBEGIN TRANSACTION;' >&3
@ -673,7 +661,7 @@ done
echo 'COMMIT;' >&3 echo 'COMMIT;' >&3
unset count unset count
endtime=$EPOCHSECONDS endtime=$(date +%s)
(( elapsedseconds = endtime - starttime - pausedtime )) (( elapsedseconds = endtime - starttime - pausedtime ))
(( days = (( days =
@ -809,7 +797,6 @@ do
tags.disc, tags.disc,
tags.genre, tags.genre,
tags.performer, tags.performer,
tags.releasecountry,
tags.title, tags.title,
tags.track, tags.track,
tags.year tags.year
@ -878,8 +865,6 @@ do
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
performer=${rest%%::AtOM:SQL:Sep::*} performer=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
releasecountry=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
title=${rest%%::AtOM:SQL:Sep::*} title=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
track=${rest%%::AtOM:SQL:Sep::*} track=${rest%%::AtOM:SQL:Sep::*}

View File

@ -1,174 +1,44 @@
[general] [general]
# This section contains parameters of the program itself.
# * max-load <load>: Integer. Defines how parallel processing will behave. AtOM
# will try to keep the 1 minute load average between <load> and <load>+1 by
# adjusting concurrency.
# Initial concurrency will be set to half of that value.
max-load 16
# * load-interval <seconds>: Integer. How often should we check the load average
# and adjust concurrency. Set this too low, and concurrency may be increased
# 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
# experience, 30 seconds is a good value.
load-interval 10
# * ionice <class> [niceness]: IO-hungry processes will be run with ionice class
# <class> and niceness [niceness] (if applicable). See man ionice for details.
ionice 3 ionice 3
max-load 6
# * temporary-directory <directory>: String. Name speaks for itself: this is load-interval 30
# where FIFOs (for communicating with sqlite) and temporary WAVE files will temporary-directory %HOME%/.atom/tmp
# be created. Note that debug logs (if enabled) will go there too. database %HOME%/.atom/atom.db
temporary-directory /tmp/AtOM-user/ debug 0
# * database <file>: String. Where the SQLite database should be stored.
database /home/user/.local/share/AtOM/atom.db
# * debug <level>: Integer.
# 0: No debug output, encoding and decoding errors logged to
# <temporary-directory>/workerN.log
# 1: Print some debug to stdout, log decoding and encoding commands to
# <temporary-directory>/workerN.log
# 3: log SQL queries to <temporary-directory>/debug.log
#debug 1
[source] [source]
# This section defines where are the files you want transcoded. path /var/lib/mpd/music
skip /last
skip /lastfm
skip /zzz-atrier
# * path <directory>: String. The root of your collection. [Ogg]
# Default: /var/lib/mpd/music path /mnt/Musique-OggQ2
path /mnt/Musique format vorbis
quality 1
# * skip <directory>: String. Files in <directory> will be ignored. Note that normalize yes
# <directory> can be any expression accepted by find. channels 2
skip /lost+found frequency 44100
skip /last
skip /lastfm
skip /zzz-atrier
[Vorbis]
# Each section not named 'general' or 'source' will define a new destination.
# Common parameters:
# Mandatory parameters:
# * enabled: Whether or not to treat this destination (1=true/0=false)
enabled 1
# * path: Where files will be written
path /mnt/Musique-OggQ2
# * format: copy, ogg, opus or mp3. Other formats may appear in the future -
# feel free to implement your preferred format.
format vorbis
# Ogg parameters:
# * quality <quality>: The quality parameter of oggenc. See man oggenc for
# more info. This is the only mode supported and planned. Still, if you want
# to be able to use bitrate settings, feel free to fork and file a pull
# request.
quality 1
# Optional parameters:
# * normalize <yes>/<no>: Normalize output files.
normalize yes
# * rename <string>: Destination files will be named according to <string>,
# after expansion of special strings:
# %{album},
# %{albumartist},
# %{artist},
# %{disc},
# %{genre},
# %{releasecountry},
# %{title},
# %{track},
# %{year}.
# Untagged files or files in unrecognized formats will not be changed.
rename %{genre}/%{albumartist}/%{year}-%{album}-%{releasecountry}/%{disc}%{track}--%{artist}-%{title}
# * fat32compat <yes>/<no>: Rename files for compatibility with FAT32
# filesystems.
fat32compat yes
# * ascii-only <yes>/<no>: Rename files for compatibility with ASCII-only
# systems.
ascii-only no
# you should not skip or copy application/octet-stream, they could be something # you should not skip or copy application/octet-stream, they could be something
# similar to "Audio file with ID3 version 2.4.0, unsynchronized frames" # similar to "Audio file with ID3 version 2.4.0, unsynchronized frames"
copy_mime-type image/*
# * skip_mime-type <mime-type>: Files with mime-type <mime-type> will not copy_mime-type text/*
# be included in that destination. For more than one mime-type, use multiple
# times, as needed. The '*' character is a wildcard.
skip_mime-type inode/x-empty
skip_mime-type audio/midi
skip_mime-type image/*
skip_mime-type text/*
skip_mime-type application/pdf
skip_mime-type application/javascript*
skip_mime-type very short file (no magic)
# * copy_mime-type <mime-type>: Same as skip_mime-type, except that files
# matching will be copied as-is to the destination. E.g. image/* will copy
# covers and other images to the destination. In fact, AtOM will try to use
# hard links instead of copies.
copy_mime-type image/*
# * copy_extension <extension>: Copy files whose name and with ".<extension>"
copy_extension txt
# * channels <number>: Files with more than <number> channels will be
# downmixed. Useful if you create files for telephony music-on-hold.
channels 2
# * frequency <hertz>: Files will be resampled as needed to <hertz>Hz
# sampling-rate. Shoutcast/Icecast streams require a constant sampling-rate.
# Telephony systems often require a sample rate of 8000Hz.
frequency 44100
# * higher-than <bitrate>: Integer. Only reencode files with bitrates higher
# then <bitrate>kbps. This only applies if sample-rate, channel count and of
# course format are equal. If unset, only files with bitrates equal to that
# of the target will be copied (actually, hardlinking will be attempted
# first). As Ogg Vorbis target quality is not defined by its bitrate, Ogg
# Vorbis files will always be reencoded if unset.
higher-than 200
[Opus] [Opus]
enabled 1
path /mnt/Musique-opus path /mnt/Musique-opus
format opus format opus
# Opus parameters:
# * bitrate <bitrate>: Set (VBR) bitrate to <bitrate>. Note that while Opus
# allows for decimal values, AtOM does not. The reason for this is simple:
# we do numeric comparisons, and Bash only manipulates integers.
bitrate 96 bitrate 96
normalize yes normalize yes
frequency 48000 frequency 48000
copy_mime-type image/* copy_mime-type image/*
copy_mime-type text/* copy_mime-type text/*
[MP3] [MP3]
enabled 1 path /mnt/Musique-mp3.test
path /mnt/Musique-mp3
format mp3 format mp3
# MP3 parameters:
# * bitrate <bitrate>: Set ABR to <bitrate>. Again, if you want CBR or any
# other mode supported by lame, please fork and file a pull request.
bitrate 96 bitrate 96
# * noresample <yes>/<no>: LAME may decide to encode your file to a lower
# sampling-rate if you use a low bitrate. Setting this to yes will
# append --resample <original file's rate>, preventing any resampling from
# happening.
noresample yes noresample yes
normalize yes normalize yes
higher-than 128 higher-than 128
@ -180,7 +50,6 @@ skip_mime-type image/*
skip_mime-type text/* skip_mime-type text/*
[asterisk] [asterisk]
enabled 1
path /mnt/Musique-asterisk path /mnt/Musique-asterisk
format vorbis format vorbis
quality 0 quality 0

View File

@ -186,7 +186,7 @@ getConfigDestination() {
destinationcopymime[$destination]="${destinationcopymime[$destination]:+${destinationcopymime[$destination]}|}$value" destinationcopymime[$destination]="${destinationcopymime[$destination]:+${destinationcopymime[$destination]}|}$value"
;; ;;
'copy_extension') 'copy_extension')
destinationcopyext[$destination]="${destinationcopyext[$destination]:+${destinationcopyext[$destination]}|}$value" destinationcopyext[$destination]="${destinationcopyext[$destination]:+${destinationcopyext[$destination]}|}\.$value$"
;; ;;
'higher-than') 'higher-than')
expr='^[0-9]*$' expr='^[0-9]*$'

View File

@ -49,13 +49,13 @@ printConfig() {
EOF EOF
[ -n "${destinationskipmime["$destination"]}" ] \ [ -n "${destinationskipmime["$destination"]}" ] \
&& echo " |Skipped mime-types|${destinationskipmime["$destination"]//\|/ && echo " |Skipped mime-types|${destinationskipmime["$destination"]//\|/
| |}" | | |}"
[ -n "${destinationcopymime["$destination"]}" ] \ [ -n "${destinationcopymime["$destination"]}" ] \
&& echo " |Copied mime-types|${destinationcopymime["$destination"]//\|/ && echo " |Copied mime-types|${destinationcopymime["$destination"]//\|/
| |}" | | |}"
[ -n "${destinationcopyext["$destination"]}" ] \ [ -n "${destinationcopyext["$destination"]}" ] \
&& echo " |Copied extensions|${destinationcopyext["$destination"]//\|/ && echo " |Copied extensions|${destinationcopyext["$destination"]//\|/
| |}" | | |}"
done done
}|column -t -s'|' }|column -t -s'|'
} }

View File

@ -60,7 +60,7 @@ path $sourcepath
# Common parameters: # Common parameters:
# Mandatory parameters: # Mandatory parameters:
# * enabled: Whether or not to treat this destination (1=true/0=false) # * enabled: Whether or not to treat this destination (1=tue/0=false)
enabled 1 enabled 1
# * path: Where files will be written # * path: Where files will be written
@ -144,7 +144,6 @@ bitrate ${destinationquality["$destination"]}
# %{artist}, # %{artist},
# %{disc}, # %{disc},
# %{genre}, # %{genre},
# %{releasecountry},
# %{title}, # %{title},
# %{track}, # %{track},
# %{year}. # %{year}.
@ -208,7 +207,8 @@ bitrate ${destinationquality["$destination"]}
done done
cat <<-EOCfg cat <<-EOCfg
# * copy_extension <extension>: Copy files whose name and with ".<extension>" # * copy_extension <extension>: Same as skip_extension, except that files
# matching will be copied as-is to the destination.
EOCfg EOCfg
destinationcopyext["$destination"]="${destinationcopyext["$destination"]}|" destinationcopyext["$destination"]="${destinationcopyext["$destination"]}|"
while [[ ${destinationcopyext["$destination"]} =~ \| ]] while [[ ${destinationcopyext["$destination"]} =~ \| ]]

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/bin/bash
currentdbversion=6 currentdbversion=5
checkDatabaseVersion() { checkDatabaseVersion() {
local dbversion local dbversion
if dbversion=$(Select atom version <<<"\"1\" = 1") if dbversion=$(Select atom version <<<"\"1\" = 1")

View File

@ -1,6 +1,5 @@
#!/usr/bin/env bash #!/bin/bash
openDatabase() { openDatabase() {
[[ -f "$database" ]] || populate_db=1
rm -f "$tempdir"/sqlite.{in,out} rm -f "$tempdir"/sqlite.{in,out}
mkfifo "$tempdir"/sqlite.{in,out} mkfifo "$tempdir"/sqlite.{in,out}
sqlite3 -bail "$database" \ sqlite3 -bail "$database" \
@ -14,7 +13,7 @@ openDatabase() {
exec 5>&3 exec 5>&3
exec 3> >(tee -a "$tempdir/debug.log" >&5) exec 3> >(tee -a "$tempdir/debug.log" >&5)
fi fi
(( populate_db )) && cat $schema >&3 cat $schema >&3
echo '.separator ::AtOM:SQL:Sep::' >&3 echo '.separator ::AtOM:SQL:Sep::' >&3
echo 'PRAGMA foreign_keys = ON;' >&3 echo 'PRAGMA foreign_keys = ON;' >&3
echo 'PRAGMA recursive_triggers = ON;' >&3 echo 'PRAGMA recursive_triggers = ON;' >&3

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
upgradedatabase_1_2() { upgradedatabase_1_2() {
local data \ local data \

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
upgradedatabase_2_3() { upgradedatabase_2_3() {
local data \ local data \

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
upgradedatabase_3_4() { upgradedatabase_3_4() {
echo "Upgrading database to version 4... (backup is $database.bak_v3)" echo "Upgrading database to version 4... (backup is $database.bak_v3)"

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
upgradedatabase_4_5() { upgradedatabase_4_5() {
echo "Upgrading database to version 5... (backup is $database.bak_v4)" echo "Upgrading database to version 5... (backup is $database.bak_v4)"
@ -21,7 +21,7 @@ upgradedatabase_4_5() {
rate, rate,
channels, channels,
bitrate, bitrate,
depth bitdepth
ON tags ON tags
BEGIN BEGIN
UPDATE destination_files SET last_change=0 UPDATE destination_files SET last_change=0

View File

@ -1,37 +0,0 @@
#!/usr/bin/env bash
upgradedatabase_5_6() {
echo "Upgrading database to version 6... (backup is $database.bak_v5)"
cp "$database" "$database.bak_v5"
echo '
ALTER TABLE tags ADD COLUMN replaygain_alb TEXT;
ALTER TABLE tags ADD COLUMN replaygain_trk TEXT;
DROP TRIGGER force_destination_update_on_tag_update;
CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
AFTER UPDATE OF
genre,
albumartist,
year,
album,
disc,
artist,
track,
title,
composer,
performer,
releasecountry,
replaygain_alb,
replaygain_trk,
rate,
channels,
bitrate,
depth
ON tags
BEGIN
UPDATE destination_files SET last_change=0
WHERE source_file_id=old.source_file;
END;
' >&3
Update atom version 6 <<<"1 = 1"
}

View File

@ -26,7 +26,7 @@ decodeSox() {
commandline+=(-c ${destinationchannels["$destination"]}) commandline+=(-c ${destinationchannels["$destination"]})
soxoptions_out+=" -c ${destinationchannels["$destination"]}" soxoptions_out+=" -c ${destinationchannels["$destination"]}"
fi fi
if (( ${depth:-0} > 16 )) if (( ${bitdepth:-0} > 16 ))
then then
commandline+=(-b 16) commandline+=(-b 16)
soxoptions_out+=" -b 16" soxoptions_out+=" -b 16"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/bin/bash
encodeFile::mp3() { encodeFile::mp3() {
lameopts=(${ionice}lame --quiet --noreplaygain) lameopts=(${ionice}lame --quiet)
lameopts+=(-v --abr ${destinationquality[$destination]}) lameopts+=(-v --abr ${destinationquality[$destination]})
[ -n "$album" ] && lameopts+=(--tl "$album" ) [ -n "$album" ] && lameopts+=(--tl "$album" )
[ -n "$artist" ] && lameopts+=(--ta "$artist") [ -n "$artist" ] && lameopts+=(--ta "$artist")
@ -13,10 +13,6 @@ encodeFile::mp3() {
[ -n "$performer" ] && lameopts+=(--tv TOPE="$performer") [ -n "$performer" ] && lameopts+=(--tv TOPE="$performer")
[ -n "$releasecountry" ] \ [ -n "$releasecountry" ] \
&& lameopts+=(--tv TXXX="MusicBrainz Album Release Country=$releasecountry") && lameopts+=(--tv TXXX="MusicBrainz Album Release Country=$releasecountry")
[ -n "$replaygain_alb" ] \
&& lameopts+=(--tv "TXXX=REPLAYGAIN_ALBUM_GAIN=$replaygain_alb")
[ -n "$replaygain_trk" ] \
&& lameopts+=(--tv "TXXX=REPLAYGAIN_TRACK_GAIN=$replaygain_trk")
[ -n "$disc" ] && lameopts+=(--tv TPOS="$disc") [ -n "$disc" ] && lameopts+=(--tv TPOS="$disc")
if (( ${destinationnoresample[$destination]:-0} == 1 )) if (( ${destinationnoresample[$destination]:-0} == 1 ))
then then

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
encodeFile::opus() { encodeFile::opus() {
opusencopts=(${ionice}opusenc --quiet) opusencopts=(${ionice}opusenc --quiet)
opusencopts+=(--bitrate ${destinationquality[$destination]}) opusencopts+=(--bitrate ${destinationquality[$destination]})
@ -13,12 +13,6 @@ encodeFile::opus() {
[ -n "$performer" ] && opusencopts+=(--comment "PERFORMER=$performer") [ -n "$performer" ] && opusencopts+=(--comment "PERFORMER=$performer")
[ -n "$releasecountry" ] \ [ -n "$releasecountry" ] \
&& opusencopts+=(--comment "RELEASECOUNTRY=$releasecountry") && opusencopts+=(--comment "RELEASECOUNTRY=$releasecountry")
[ -n "$replaygain_alb" ] \
&& opusencopts+=(--comment) \
&& opusencopts+=("REPLAYGAIN_ALBUM_GAIN=$replaygain_alb")
[ -n "$replaygain_trk" ] \
&& opusencopts+=(--comment) \
&& opusencopts+=("REPLAYGAIN_TRACK_GAIN=$replaygain_trk")
[ -n "$title" ] && opusencopts+=(--title "$title") [ -n "$title" ] && opusencopts+=(--title "$title")
[ -n "$track" ] && opusencopts+=(--comment "TRACKNUMBER=${track%/*}") [ -n "$track" ] && opusencopts+=(--comment "TRACKNUMBER=${track%/*}")
[ -n "${track#*/}" ] && opusencopts+=(--comment "TRACKTOTAL=${track#*/}") [ -n "${track#*/}" ] && opusencopts+=(--comment "TRACKTOTAL=${track#*/}")

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
encodeFile::vorbis() { encodeFile::vorbis() {
oggencopts=(${ionice}oggenc -Q -q ${destinationquality[$destination]}) oggencopts=(${ionice}oggenc -Q -q ${destinationquality[$destination]})
[ -n "$albumartist" ] && oggencopts+=(-c "ALBUMARTIST=$albumartist") [ -n "$albumartist" ] && oggencopts+=(-c "ALBUMARTIST=$albumartist")
@ -9,11 +9,7 @@ encodeFile::vorbis() {
[ -n "$genre" ] && oggencopts+=(-G "$genre") [ -n "$genre" ] && oggencopts+=(-G "$genre")
[ -n "$performer" ] && oggencopts+=(-c "PERFORMER=$performer") [ -n "$performer" ] && oggencopts+=(-c "PERFORMER=$performer")
[ -n "$releasecountry" ] \ [ -n "$releasecountry" ] \
&& oggencopts+=(-c "RELEASECOUNTRY=$releasecountry") && oggencopts+=(--comment "RELEASECOUNTRY=$releasecountry")
[ -n "$replaygain_alb" ] \
&& oggencopts+=(-c "REPLAYGAIN_ALBUM_GAIN=$replaygain_alb")
[ -n "$replaygain_trk" ] \
&& oggencopts+=(-c "REPLAYGAIN_TRACK_GAIN=$replaygain_trk")
[ -n "$title" ] && oggencopts+=(-t "$title") [ -n "$title" ] && oggencopts+=(-t "$title")
[ -n "$track" ] && oggencopts+=(-N "$track") [ -n "$track" ] && oggencopts+=(-N "$track")
[ -n "$year" ] && oggencopts+=(-d "$year") [ -n "$year" ] && oggencopts+=(-d "$year")

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
getFiles() { getFiles() {
scantime=$EPOCHSECONDS scantime=$(date +%s)
for prune_expression in "${skippeddirectories[@]}" for prune_expression in "${skippeddirectories[@]}"
do do
prunes+=( -path "$sourcepath$prune_expression" -prune -o ) prunes+=( -path "$sourcepath$prune_expression" -prune -o )

View File

@ -251,7 +251,6 @@ setupDestination() {
%{artist}, %{artist},
%{disc}, %{disc},
%{genre}, %{genre},
%{releasecountry},
%{title}, %{title},
%{track}, %{track},
%{year}. %{year}.
@ -388,16 +387,16 @@ setupDestination() {
copiedmimes+=("${destinationcopymime["$destination"]%%|*}") copiedmimes+=("${destinationcopymime["$destination"]%%|*}")
destinationcopymime["$destination"]="${destinationcopymime["$destination"]#*|}" destinationcopymime["$destination"]="${destinationcopymime["$destination"]#*|}"
done done
[ -n "${destinationcopymime["$destination"]}" ] \ [ -n "${destinationcopymime["$destination"]}" ] \
&& copiedmimes+=("${destinationcopymime["$destination"]}") && copiedmimes+=("${destinationcopymime["$destination"]}")
count=${#copiedmimes[@]} count=${#copiedmimes[@]}
unset destinationcopymime["$destination"] unset destinationcopymime["$destination"]
for (( i=0 ; 1 ; i++ )) for (( i=0 ; 1 ; i++ ))
do do
read \ read \
-e \ -e \
${copiedmimes[i]+-i"${copiedmimes[i]}"} \ ${copiedmimes[i]+-i"${copiedmimes[i]}"} \
-p 'Copy mime-type: ' \ -p 'Copy mime-type: ' \
value value
if [ -n "$value" ] if [ -n "$value" ]
then then
@ -410,44 +409,6 @@ setupDestination() {
fi fi
done done
unset copiedmimes unset copiedmimes
cat <<-EODesc
Copy extensions (extension, string):
Files with extension <extension> will be copied as-is to the
destination. E.g. .jpg will copy covers and other images to the
destination.
This prompt will loop until an empty string is encountered.
EODesc
while [[ ${destinationcopyext["$destination"]} =~ \| ]]
do
copiedexts+=("${destinationcopyext["$destination"]%%|*}")
destinationcopyext["$destination"]="${destinationcopyext["$destination"]#*|}"
done
[ -n "${destinationcopyext["$destination"]}" ] \
&& copiedexts+=("${destinationcopyext["$destination"]}")
count=${#copiedexts[@]}
unset destinationcopyext["$destination"]
for (( i=0 ; 1 ; i++ ))
do
read \
-e \
${copiedexts[i]+-i"${copiedexts[i]}"} \
-p 'Copy extension: ' \
value
if [ -n "$value" ]
then
destinationcopyext[$destination]="${destinationcopyext[$destination]:+${destinationcopyext[$destination]}|}$value"
elif (( i < count ))
then
continue
else
break
fi
done
unset copiedexts
cat <<-EODesc cat <<-EODesc
Channels (integer): Channels (integer):

View File

@ -24,7 +24,6 @@ Completion is available for prompts asking for a paths or filenames.
destinationchannels \ destinationchannels \
destinationfat32compat \ destinationfat32compat \
destinationcopymime \ destinationcopymime \
destinationcopyext \
destinationformat \ destinationformat \
destinationfrequency \ destinationfrequency \
destinationid \ destinationid \
@ -41,7 +40,6 @@ Completion is available for prompts asking for a paths or filenames.
destinationchannels \ destinationchannels \
destinationfat32compat \ destinationfat32compat \
destinationcopymime \ destinationcopymime \
destinationcopyext \
destinationformat \ destinationformat \
destinationfrequency \ destinationfrequency \
destinationid \ destinationid \
@ -76,7 +74,7 @@ Completion is available for prompts asking for a paths or filenames.
esac esac
;; ;;
esac esac
read -p'Run index and conversion now? [Y/n] ' do_run read -p'Run now? [Y/n] ' do_run
case $do_run in case $do_run in
n) exit ;; n) exit ;;
*) ;; *) ;;

65
lib/tags/ffmpeg Normal file
View File

@ -0,0 +1,65 @@
#!/bin/bash
getInfosffmpeg_version='ffmpeg-7'
tagreaders+=( "$getInfosffmpeg_version" )
getInfos::ffmpeg() {
tagreader="$getInfosffmpeg_version"
local allinfos=$(
ffprobe -show_streams \
-i "$sourcepath/$filename" 2>&1 \
|sed '
/^Input/,/.* Audio: /{s/ *: */=/}
s/^[[:space:]]*//
s/\0//g'
)
local metadata=$(
echo -e "$allinfos" \
|sed -n '/Metadata=/,/\[STREAM\]/p'
)
local fmt_infos=$(
echo -e "$allinfos" \
|sed -n \
'/codec_type=audio/,/\[STREAM\]/{
/^\(sample_fmt\|sample_rate\|bit_rate\|channels\)=/{
p
}
}'
)
local infos="$metadata"
albumartist=$(gettag album_artist)
album=$(gettag album)
artist=$(gettag artist)
composer=$(gettag composer)
disc=$(gettag disc)
genre=$(gettag genre)
performer=$(gettag TOPE)
releasecountry=$(gettag releasecountry)
[[ -z "$releasecountry" ]] && releasecountry=$(gettag "MusicBrainz Album Release Country")
title=$(gettag title)
tracknum=$(gettag track)
year=$(gettag date)
expr='^[0-9]*$'
if [ -n "$genre" ] && [[ $genre =~ $expr ]]
then
genre="${id3genres[$genre]}"
fi
infos="$fmt_infos"
channels=$(gettag channels)
rate=$(gettag 'sample_rate')
case $rate in
96) rate=96000;;
48) rate=48000;;
441) rate=44100;;
32) rate=32000;;
24) rate=24000;;
225) rate=22500;;
esac
bitrate=$(gettag 'bit_rate')
bitdepth=$(gettag 'sample_fmt')
bitdepth=${bitdepth//[A-z]/}
if [[ $bitrate == N/A ]]
then
unset bitrate
else
bitrate=$((bitrate / 1000))
fi
}

50
lib/tags/flac Normal file
View File

@ -0,0 +1,50 @@
#!/bin/bash
getInfosFLAC_version='FLAC-4'
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=RELEASECOUNTRY \
--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)
releasecountry=$(gettag releasecountry)
title=$(gettag title)
tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal)
year=$(gettag date)
if [ -n "$tracknum" -a -n "$tracktotal" ]
then
tracknum="$tracknum/$tracktotal"
fi
year=$(gettag DATE)
{
read rate
read channels
read bitdepth
} < <(
metaflac \
--show-sample-rate \
--show-channels \
--show-bps \
"$sourcepath/$filename"
)
}

View File

@ -1,54 +0,0 @@
#!/usr/bin/env bash
getInfosFLAC_version='FLAC-5'
tagreaders+=( "$getInfosFLAC_version" )
getInfos::FLAC() {
local \
infos \
tagreader="$getInfosFLAC_version"
infos=$(
metaflac \
--show-sample-rate \
--show-channels \
--show-bps \
--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=RELEASECOUNTRY \
--show-tag=REPLAYGAIN_ALBUM_GAIN \
--show-tag=REPLAYGAIN_TRACK_GAIN \
--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)
releasecountry=$(gettag releasecountry)
replaygain_alb=$(gettag replaygain_album_gain)
replaygain_trk=$(gettag replaygain_track_gain)
title=$(gettag title)
tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal)
year=$(gettag date)
if [ -n "$tracknum" -a -n "$tracktotal" ]
then
tracknum="$tracknum/$tracktotal"
fi
year=$(gettag DATE)
{
read rate
read channels
read depth
} <<<"$infos"
}

View File

@ -1,75 +0,0 @@
#!/usr/bin/env bash
getInfosffmpeg_version='ffmpeg-9'
tagreaders+=( "$getInfosffmpeg_version" )
getInfos::ffmpeg() {
tagreader="$getInfosffmpeg_version"
local \
infos \
infos=$(
ffprobe -v error \
-show_entries " \
format_tags= \
album_artist, \
album, \
artist, \
composer, \
disc, \
genre, \
TOPE, \
releasecountry, \
'MusicBrainz Album Release Country',\
title, \
track, \
date, \
replaygain_track_gain, \
replaygain_album_gain \
:stream= \
bit_rate, \
channels, \
sample_rate, \
" \
-of default=noprint_wrappers=1 \
-i "$sourcepath/$filename" \
| egrep -v '=N/A$'
)
albumartist=$(gettag TAG:album_artist)
album=$(gettag TAG:album)
artist=$(gettag TAG:artist)
composer=$(gettag TAG:composer)
disc=$(gettag TAG:disc)
genre=$(gettag TAG:genre)
performer=$(gettag TAG:TOPE)
releasecountry=$(gettag TAG:releasecountry)
[[ -z "$releasecountry" ]] \
&& releasecountry=$(gettag "TAG:MusicBrainz Album Release Country")
replaygain_alb=$(gettag TAG:replaygain_album_gain)
replaygain_trk=$(gettag TAG:replaygain_track_gain)
title=$(gettag TAG:title)
tracknum=$(gettag TAG:track)
year=$(gettag TAG:date)
expr='^[0-9]*$'
if [ -n "$genre" ] && [[ $genre =~ $expr ]]
then
genre="${id3genres[$genre]}"
fi
channels=$(gettag channels)
rate=$(gettag 'sample_rate')
case $rate in
96) rate=96000;;
48) rate=48000;;
441) rate=44100;;
32) rate=32000;;
24) rate=24000;;
225) rate=22500;;
esac
bitrate=$(gettag 'bit_rate')
depth=$(gettag 'sample_fmt')
depth=${depth//[A-z]/}
if [[ $bitrate == N/A ]]
then
unset bitrate
else
bitrate=$((bitrate / 1000))
fi
}

View File

@ -1,11 +1,8 @@
#!/usr/bin/env bash #!/bin/bash
getInfosOpus_version='Opus-4' getInfosOpus_version='Opus-3'
tagreaders+=( "$getInfosOpus_version" ) tagreaders+=( "$getInfosOpus_version" )
getInfos::Opus() { getInfos::Opus() {
tagreader="$getInfosOpus_version" tagreader="$getInfosOpus_version"
local \
infos \
infos=$( infos=$(
opusinfo "$sourcepath/$filename" \ opusinfo "$sourcepath/$filename" \
| sed 's/\t//' | sed 's/\t//'
@ -18,8 +15,6 @@ getInfos::Opus() {
genre=$(gettag genre) genre=$(gettag genre)
performer=$(gettag performer) performer=$(gettag performer)
releasecountry=$(gettag releasecountry) releasecountry=$(gettag releasecountry)
replaygain_alb=$(gettag replaygain_album_gain)
replaygain_trk=$(gettag replaygain_track_gain)
title=$(gettag title) title=$(gettag title)
tracknum=$(gettag tracknumber) tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal) tracktotal=$(gettag tracktotal)

View File

@ -1,11 +1,8 @@
#!/usr/bin/env bash #!/bin/bash
getInfosSoxi_version='soxi-3' getInfosSoxi_version='soxi-2'
tagreaders+=( "$getInfosSoxi_version" ) tagreaders+=( "$getInfosSoxi_version" )
getInfos::soxi() { getInfos::soxi() {
tagreader="$getInfosSoxi_version" tagreader="$getInfosSoxi_version"
local \
infos \
infos=$( infos=$(
soxi "$sourcepath/$filename" \ soxi "$sourcepath/$filename" \
| grep -v METADATA_BLOCK_PICTURE | grep -v METADATA_BLOCK_PICTURE
@ -18,8 +15,6 @@ getInfos::soxi() {
genre=$(gettag genre) genre=$(gettag genre)
performer=$(gettag performer) performer=$(gettag performer)
releasecountry=$(gettag releasecountry) releasecountry=$(gettag releasecountry)
replaygain_alb=$(gettag replaygain_album_gain)
replaygain_trk=$(gettag replaygain_track_gain)
title=$(gettag title) title=$(gettag title)
tracknum=$(gettag tracknumber) tracknum=$(gettag tracknumber)
tracktotal=$(gettag tracktotal) tracktotal=$(gettag tracktotal)
@ -34,6 +29,6 @@ getInfos::soxi() {
bitrate=$(gettag 'bit rate') bitrate=$(gettag 'bit rate')
bitrate=${bitrate%k} bitrate=${bitrate%k}
bitrate=${bitrate%%.*} bitrate=${bitrate%%.*}
depth=$(gettag precision) bitdepth=$(gettag precision)
depth=${depth%-bit} bitdepth=${bitdepth%-bit}
} }

View File

@ -1,7 +1,5 @@
#!/usr/bin/env bash #!/bin/bash
updateTags() { updateTags() {
local reader \
for reader in "${tagreaders[@]}" for reader in "${tagreaders[@]}"
do do
tagreaderclause+="${tagreaderclause:+ AND }NOT tags.tagreader = \"$reader\"" tagreaderclause+="${tagreaderclause:+ AND }NOT tags.tagreader = \"$reader\""
@ -21,8 +19,6 @@ updateTags() {
tags.genre, tags.genre,
tags.performer, tags.performer,
tags.releasecountry, tags.releasecountry,
tags.replaygain_alb,
tags.replaygain_trk,
tags.title, tags.title,
tags.track, tags.track,
tags.year, tags.year,
@ -88,10 +84,6 @@ echo '
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
oldreleasecountry=${rest%%::AtOM:SQL:Sep::*} oldreleasecountry=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
oldreplaygain_alb=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
oldreplaygain_trk=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
oldtitle=${rest%%::AtOM:SQL:Sep::*} oldtitle=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::} rest=${rest#*::AtOM:SQL:Sep::}
oldtrack=${rest%%::AtOM:SQL:Sep::*} oldtrack=${rest%%::AtOM:SQL:Sep::*}
@ -105,7 +97,7 @@ echo '
oldbitrate=${rest%%::AtOM:SQL:Sep::*} oldbitrate=${rest%%::AtOM:SQL:Sep::*}
((++count)) ((++count))
(( cron )) || echo -en "\rTags: $((count*100/filecount))%" (( cron )) || echo -en "\rTags: $((count*100/filecount))%"
if (( count % 100 == 0 )) if (( count % 1000 == 0 ))
then then
echo 'COMMIT;BEGIN TRANSACTION;' >&3 echo 'COMMIT;BEGIN TRANSACTION;' >&3
(( debug )) \ (( debug )) \
@ -117,13 +109,11 @@ echo '
[[ $oldalbumartist != "$albumartist" ]]&&uaa=1 [[ $oldalbumartist != "$albumartist" ]]&&uaa=1
[[ $oldartist != "$artist" ]]&& uar=1 [[ $oldartist != "$artist" ]]&& uar=1
[[ $oldcomposer != "$composer" ]]&& uco=1 [[ $oldcomposer != "$composer" ]]&& uco=1
[[ $olddepth != "$depth" ]]&& ude=1 [[ $olddepth != "$bitdepth" ]]&& ude=1
[[ $olddisc != "$disc" ]]&& udi=1 [[ $olddisc != "$disc" ]]&& udi=1
[[ $oldgenre != "$genre" ]]&& uge=1 [[ $oldgenre != "$genre" ]]&& uge=1
[[ $oldperformer != "$performer" ]]&& upe=1 [[ $oldperformer != "$performer" ]]&& upe=1
[[ $oldreleasecountry != "$releasecountry" ]]&& urc=1 [[ $oldreleasecountry != "$releasecountry" ]]&& urc=1
[[ $oldreplaygain_alb != "$replaygain_alb" ]]&& urpa=1
[[ $oldreplaygain_trk != "$replaygain_trk" ]]&& urpt=1
[[ $oldtitle != "$title" ]]&& uti=1 [[ $oldtitle != "$title" ]]&& uti=1
[[ $oldtrack != "$tracknum" ]]&& utr=1 [[ $oldtrack != "$tracknum" ]]&& utr=1
[[ $oldyear != "$year" ]]&& uye=1 [[ $oldyear != "$year" ]]&& uye=1
@ -135,13 +125,11 @@ echo '
${uaa:+albumartist "${albumartist:+::AtOM:FT::}${albumartist:-NULL}"}\ ${uaa:+albumartist "${albumartist:+::AtOM:FT::}${albumartist:-NULL}"}\
${uar:+artist "${artist:+::AtOM:FT::}${artist:-NULL}"}\ ${uar:+artist "${artist:+::AtOM:FT::}${artist:-NULL}"}\
${uco:+composer "${composer:+::AtOM:FT::}${composer:-NULL}"}\ ${uco:+composer "${composer:+::AtOM:FT::}${composer:-NULL}"}\
${ude:+depth "${depth:-NULL}"} \ ${ude:+depth "${bitdepth:-NULL}"} \
${udi:+disc "${disc:-NULL}"} \ ${udi:+disc "${disc:-NULL}"} \
${uge:+genre "${genre:-NULL}"} \ ${uge:+genre "${genre:-NULL}"} \
${upe:+performer "${performer:+::AtOM:FT::}${performer:-NULL}"}\ ${upe:+performer "${performer:+::AtOM:FT::}${performer:-NULL}"}\
${urc:+releasecountry "${releasecountry:+::AtOM:FT::}${releasecountry:-NULL}"}\ ${urc:+releasecountry "${releasecountry:+::AtOM:FT::}${releasecountry:-NULL}"}\
${urpa:+replaygain_alb "${replaygain_alb:-NULL}"}\
${urpt:+replaygain_trk "${replaygain_trk:-NULL}"}\
${uti:+title "${title:+::AtOM:FT::}${title:-NULL}"}\ ${uti:+title "${title:+::AtOM:FT::}${title:-NULL}"}\
${utr:+track "${track:+::AtOM:FT::}${tracknum:-NULL}"}\ ${utr:+track "${track:+::AtOM:FT::}${tracknum:-NULL}"}\
${uye:+year "${year:-NULL}"} \ ${uye:+year "${year:-NULL}"} \
@ -150,58 +138,37 @@ echo '
${uch:+channels "${channels:-NULL}"} \ ${uch:+channels "${channels:-NULL}"} \
${ubi:+bitrate "${bitrate:-NULL}"} \ ${ubi:+bitrate "${bitrate:-NULL}"} \
tagreader "$tagreader" \ tagreader "$tagreader" \
>/dev/null <<<"source_file = $sourcefileid" >/dev/null <<<"source_file = $sourcefileid"
unset genre \ unset genre \
albumartist \ albumartist \
year \ year \
album \ album \
disc \ disc \
artist \ artist \
tracknum \ tracknum \
title \ title \
composer \ composer \
performer \ performer \
releasecountry \ releasecountry \
replaygain_alb \ rate \
replaygain_trk \ bitdepth \
rate \ bitrate \
depth \ channels \
bitrate \ ual \
channels \ uaa \
oldgenre \ uar \
oldalbumartist \ uco \
oldyear \ ude \
oldalbum \ udi \
olddisc \ uge \
oldartist \ upe \
oldtracknum \ urc \
oldtitle \ uti \
oldcomposer \ utr \
oldperformer \ uye \
oldreleasecountry \ ura \
oldreplaygain_alb \ uch \
oldreplaygain_trk \ ubi
oldrate \
olddepth \
oldbitrate \
oldchannels \
ual \
uaa \
uar \
uco \
ude \
udi \
uge \
upe \
urc \
urpa \
urpt \
uti \
utr \
uye \
ura \
uch \
ubi
fi fi
done done
echo 'COMMIT;' >&3 echo 'COMMIT;' >&3

View File

@ -162,5 +162,3 @@ Sanity checks raised $sanitywarn warnings... Hit Control-C to abort." >&2
fi fi
fi fi
} }
# vim:set ts=8 sw=8:

View File

@ -17,224 +17,213 @@ master() {
return 0 return 0
fi fi
until (( active == concurrency || remaining == 0 )) echo '
do SELECT COUNT(*)
echo ' FROM tasks
SELECT COUNT(*) WHERE status = 0
FROM tasks AND requires IN (
WHERE status = 0 SELECT id
AND requires IN ( FROM tasks
SELECT id WHERE status = 4
FROM tasks );
WHERE status = 4
);
SELECT SELECT
id, id,
source_file, source_file,
cmd_arg0, cmd_arg0,
cmd_arg1, cmd_arg1,
cmd_arg2, cmd_arg2,
cmd_arg3, cmd_arg3,
cmd_arg4, cmd_arg4,
cmd_arg5, cmd_arg5,
cmd_arg6, cmd_arg6,
cmd_arg7, cmd_arg7,
cmd_arg8, cmd_arg8,
cmd_arg9, cmd_arg9,
cmd_arg10, cmd_arg10,
cmd_arg11, cmd_arg11,
cmd_arg12, cmd_arg12,
cmd_arg13, cmd_arg13,
cmd_arg14, cmd_arg14,
cmd_arg15, cmd_arg15,
cmd_arg16, cmd_arg16,
cmd_arg17, cmd_arg17,
cmd_arg18, cmd_arg18,
cmd_arg19, cmd_arg19,
cmd_arg20, cmd_arg20,
cmd_arg21, cmd_arg21,
cmd_arg22, cmd_arg22,
cmd_arg23, cmd_arg23,
cmd_arg24, cmd_arg24,
cmd_arg25, cmd_arg25,
cmd_arg26, cmd_arg26,
cmd_arg27, cmd_arg27,
cmd_arg28, cmd_arg28,
cmd_arg29, cmd_arg29,
cmd_arg30, cmd_arg30,
cmd_arg31, cmd_arg31,
cmd_arg32, cmd_arg32,
cmd_arg33, cmd_arg33,
cmd_arg34, cmd_arg34,
cmd_arg35, cmd_arg35,
cmd_arg36, cmd_arg36,
cmd_arg37, cmd_arg37,
cmd_arg38, cmd_arg38,
cmd_arg39, cmd_arg39,
cmd_arg40, cmd_arg40,
cmd_arg41, cmd_arg41,
cmd_arg42, cmd_arg42,
cmd_arg43, cmd_arg43,
cmd_arg44, cmd_arg44,
cmd_arg45, cmd_arg45,
cmd_arg46, cmd_arg46,
cmd_arg47, cmd_arg47,
cmd_arg48, cmd_arg48,
cmd_arg49, cmd_arg49,
cmd_arg50, cmd_arg50,
cmd_arg51, cmd_arg51,
cmd_arg52, cmd_arg52,
cmd_arg53, cmd_arg53,
cmd_arg54, cmd_arg54,
cmd_arg55, cmd_arg55,
cmd_arg56, cmd_arg56,
cmd_arg57, cmd_arg57,
cmd_arg58, cmd_arg58,
cmd_arg59, cmd_arg59,
cleanup, cleanup,
fileid, fileid,
filename filename
FROM tasks FROM tasks
WHERE status = 0 WHERE status = 0
AND requires IN ( AND requires IN (
SELECT id SELECT id
FROM tasks FROM tasks
WHERE status = 4 WHERE status = 4
ORDER BY source_file ORDER BY source_file
/* LIMIT 1 */ /* LIMIT 1 */
) )
ORDER BY source_file ORDER BY source_file
LIMIT 1; LIMIT 1;
'>&3 '>&3
read -u4 ready read -u4 ready
if (( ready > 0 )) if (( ready > 0 ))
then then
createworker createworker
continue return 0
fi fi
echo ' echo '
SELECT COUNT(*) SELECT COUNT(*)
FROM tasks FROM tasks
WHERE status = 0 WHERE status = 0
AND requires is NULL; AND requires is NULL;
SELECT SELECT
id, id,
source_file, source_file,
cmd_arg0, cmd_arg0,
cmd_arg1, cmd_arg1,
cmd_arg2, cmd_arg2,
cmd_arg3, cmd_arg3,
cmd_arg4, cmd_arg4,
cmd_arg5, cmd_arg5,
cmd_arg6, cmd_arg6,
cmd_arg7, cmd_arg7,
cmd_arg8, cmd_arg8,
cmd_arg9, cmd_arg9,
cmd_arg10, cmd_arg10,
cmd_arg11, cmd_arg11,
cmd_arg12, cmd_arg12,
cmd_arg13, cmd_arg13,
cmd_arg14, cmd_arg14,
cmd_arg15, cmd_arg15,
cmd_arg16, cmd_arg16,
cmd_arg17, cmd_arg17,
cmd_arg18, cmd_arg18,
cmd_arg19, cmd_arg19,
cmd_arg20, cmd_arg20,
cmd_arg21, cmd_arg21,
cmd_arg22, cmd_arg22,
cmd_arg23, cmd_arg23,
cmd_arg24, cmd_arg24,
cmd_arg25, cmd_arg25,
cmd_arg26, cmd_arg26,
cmd_arg27, cmd_arg27,
cmd_arg28, cmd_arg28,
cmd_arg29, cmd_arg29,
cmd_arg30, cmd_arg30,
cmd_arg31, cmd_arg31,
cmd_arg32, cmd_arg32,
cmd_arg33, cmd_arg33,
cmd_arg34, cmd_arg34,
cmd_arg35, cmd_arg35,
cmd_arg36, cmd_arg36,
cmd_arg37, cmd_arg37,
cmd_arg38, cmd_arg38,
cmd_arg39, cmd_arg39,
cmd_arg40, cmd_arg40,
cmd_arg41, cmd_arg41,
cmd_arg42, cmd_arg42,
cmd_arg43, cmd_arg43,
cmd_arg44, cmd_arg44,
cmd_arg45, cmd_arg45,
cmd_arg46, cmd_arg46,
cmd_arg47, cmd_arg47,
cmd_arg48, cmd_arg48,
cmd_arg49, cmd_arg49,
cmd_arg50, cmd_arg50,
cmd_arg51, cmd_arg51,
cmd_arg52, cmd_arg52,
cmd_arg53, cmd_arg53,
cmd_arg54, cmd_arg54,
cmd_arg55, cmd_arg55,
cmd_arg56, cmd_arg56,
cmd_arg57, cmd_arg57,
cmd_arg58, cmd_arg58,
cmd_arg59, cmd_arg59,
cleanup, cleanup,
fileid, fileid,
filename filename
FROM tasks FROM tasks
WHERE status = 0 WHERE status = 0
AND requires is NULL AND requires is NULL
ORDER BY source_file ORDER BY source_file
LIMIT 1; LIMIT 1;
' >&3 ' >&3
read -u4 ready read -u4 ready
if (( active == 0 && ready == 0 )) if (( active == 0 && ready == 0 ))
then then
dumpfile="$tempdir/tasks-$(date -Iseconds).csv" dumpfile="$tempdir/tasks-$(date -Iseconds).csv"
cat <<-EOF cat <<-EOF
$remaining TASKS LEFT, NONE READY! $remaining TASKS LEFT, NONE READY!
Something went wrong, dumping tasks table to $dumpfile Something went wrong, dumping tasks table to $dumpfile
EOF EOF
cat >&3 <<-EOSQL cat >&3 <<-EOSQL
.mode csv .mode csv
.headers on .headers on
.output $dumpfile .output $dumpfile
SELECT * from tasks; SELECT * from tasks;
.mode list .mode list
.headers off .headers off
.output stdout .output stdout
COMMIT; COMMIT;
EOSQL EOSQL
closeDatabase closeDatabase
echo "Waiting for children to come back home..." echo "Waiting for children to come back home..."
wait wait
echo $'\nGood luck!' echo $'\nGood luck!'
exit 1 exit 1
elif (( ready == 0 )) elif (( ready == 0 ))
then then
sleep 0.1 sleep 0.1
break else
else createworker
createworker fi
fi
echo '
SELECT COUNT(*)
FROM tasks
WHERE status = 0;
'>&3
read -u4 remaining
done
fi fi
} }

View File

@ -59,8 +59,6 @@ CREATE TABLE IF NOT EXISTS tags (
composer TEXT, composer TEXT,
performer TEXT, performer TEXT,
releasecountry TEXT, releasecountry TEXT,
replaygain_alb TEXT,
replaygain_trk TEXT,
depth INTEGER, depth INTEGER,
rate INTEGER, rate INTEGER,
channels INTEGER, channels INTEGER,
@ -133,12 +131,10 @@ CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
composer, composer,
performer, performer,
releasecountry, releasecountry,
replaygain_alb,
replaygain_trk,
rate, rate,
channels, channels,
bitrate, bitrate,
depth bitdepth
ON tags ON tags
BEGIN BEGIN
UPDATE destination_files SET last_change=0 UPDATE destination_files SET last_change=0

View File

@ -38,7 +38,7 @@ LC_ALL=C
shopt -s extglob shopt -s extglob
source "$SHAREDIR"/id3genres source ./share/id3genres
for function in "$LIBDIR"/*/* for function in "$LIBDIR"/*/*
do do
@ -287,12 +287,12 @@ cat <<-EOBrag
# #
# $0 $args # $0 $args
# #
# Last database update: $(printf "%(%x %X)T" "$lastupdate") # Last database update: $(date -d @$lastupdate +'%x %X')
EOBrag EOBrag
printDate() { printDate() {
printf "%("${timeformat:-%x %X}")T" "$1" date -d"@$1" +"${timeformat:-%x %X}"
} }
for index in ${!show[@]} for index in ${!show[@]}