Compare commits

..

42 Commits

Author SHA1 Message Date
ScriptFanix
7a359ad2d6 Merge branch 'dev' into 'master'
v1.0.4 last minute fixes

See merge request atom/AtOM!32
2025-10-13 18:21:25 +02:00
Vincent Riquer
75159a4e2b Hotfix: createindex: fix ID3v1 genre index path 2025-10-13 18:20:54 +02:00
Vincent Riquer
325bdb3c96 Hotfix: missing quote in createindex 2025-10-13 18:20:54 +02:00
Vincent Riquer
2b5bf06e58 Hotfix: commit more often when reading tags 2025-10-13 18:20:54 +02:00
ScriptFanix
3a6c7bfc9c Merge branch 'dev' into 'master'
Bugfix release v1.0.4

Closes #26

See merge request atom/AtOM!30
2025-10-11 22:31:16 +02:00
ScriptFanix
f3e4aed71e Merge branch '26-ffmpeg-tags-are-always-null' into 'dev'
Resolve "ffmpeg tags are always NULL"

See merge request atom/AtOM!29
2025-10-11 22:23:17 +02:00
ScriptFanix
a0756b170c Resolve "ffmpeg tags are always NULL" 2025-10-11 22:23:16 +02:00
Vincent Riquer
1d7a09fcff quickfix: replace calls to date with builtin printf or $EPOCHSECONDS 2025-08-08 20:19:51 +02:00
ScriptFanix
1df976bcae Revert "getInfos::guess skeleton"
This reverts commit 0ea0dbe09d59703a2b468a9c96185a148eebc1aa
2025-04-30 02:45:37 +02:00
Vincent Riquer
0ea0dbe09d getInfos::guess skeleton 2025-04-30 02:41:29 +02:00
ScriptFanix
b61dddcd67 Edit README.md 2025-04-29 23:54:59 +02:00
Vincent Riquer
73652a329b Update changelog 2025-04-16 00:03:23 +02:00
Vincent Riquer
ad6d820496 doc: Update example.cfg
Fixes #23
2025-04-15 23:58:14 +02:00
ScriptFanix
af40b872a7 Merge branch '20-bug-setup-is-not-aware-of-copy_extension' into 'master'
Resolve "BUG: Setup is not aware of `copy_extension`"

Closes #20

See merge request atom/AtOM!26
2025-04-15 21:36:31 +00:00
ScriptFanix
95ce31a54a Resolve "BUG: Setup is not aware of copy_extension" 2025-04-15 21:36:31 +00:00
Vincent Riquer
29e8616ff9 README update URL 2025-04-05 06:28:11 +02:00
Vincent Riquer
9cdce7752a README update URL 2025-04-05 06:20:50 +02:00
Vincent Riquer
f7522e5f34 Merge branch '24-release-country-issues' into 'master'
Resolve "release country issues"

Closes #19, #21, #22, and #24

See merge request atom/AtOM!25
2025-04-03 22:51:20 +00:00
Vincent Riquer
6a888f02e7 Resolve "release country issues" 2025-04-03 22:51:19 +00:00
Vincent Riquer
73900210ad Edit CHANGELOG.md 2025-04-02 23:34:16 +00:00
Vincent Riquer
556ce4d142 Edit CHANGELOG.md 2025-04-02 23:28:46 +00:00
Vincent Riquer
c7bea0d3a6 Merge branch '17-read-and-copy-replaygain' into 'master'
Resolve "Read and copy replaygain"

Closes #17

See merge request atom/AtOM!24
2025-04-02 23:22:18 +00:00
Vincent Riquer
806a0f16a7 FEAT: Read and copy replaygain 2025-04-02 23:22:18 +00:00
Vincent Riquer
89100a2949 Move TODO to #18 2025-04-01 01:13:03 +00:00
Vincent Riquer
6cde6b4ada Merge branch 'fix-infinite-loop' into 'master'
fix infinite loop at end of task list

See merge request atom/AtOM!23
2025-03-15 02:10:54 +00:00
Vincent Riquer
0a9a5335bb fix infinite loop at end of task list 2025-03-15 03:01:27 +01:00
Vincent Riquer
2e3c47071f Merge branch '16-unable-to-saturate-cpus-on-sufficiently-powerfulm-hartdware' into 'master'
Resolve "Unable to saturate CPUs on sufficiently powerfulm hartdware"

Closes #16

See merge request atom/AtOM!21
2025-03-14 03:14:57 +00:00
Vincent Riquer
aaaad2ce9a Resolve "Unable to saturate CPUs on sufficiently powerfulm hartdware" 2025-03-14 03:14:57 +00:00
Vincent Riquer
0fd1fae6dc Merge branch '15-temp-directory-not-created-for-toys' into 'master'
Resolve "Temp directory not created for toys"

Closes #15

See merge request atom/AtOM!20
2025-03-13 23:24:59 +00:00
Vincent Riquer
dd72a6b0ba Resolve "Temp directory not created for toys" 2025-03-13 23:24:59 +00:00
Vincent Riquer
0dd962fb8c Enhancement: slight performance improve
atom: don't call `date` to get the timestamp multiple times in the main loop
2025-02-11 21:50:14 +01:00
Vincent Riquer
042cd72ecd Merge branch '12-update-changelog-for-v1-0-2' into 'master'
Resolve "Update CHANGELOG for v1.0.2"

Closes #12

See merge request atom/AtOM!17
2025-02-10 19:04:14 +00:00
Vincent Riquer
8effee243a Resolve "Update CHANGELOG for v1.0.2" 2025-02-10 19:04:13 +00:00
Vincent Riquer
45433fa214 Merge branch '10-bug-releasecountry-change-should-update-dest-files' into 'master'
Resolve "BUG: releasecountry change should update dest files"

Closes #10

See merge request atom/AtOM!16
2025-02-10 18:57:38 +00:00
Vincent Riquer
92a5ba0234 Resolve "BUG: releasecountry change should update dest files" 2025-02-10 18:57:38 +00:00
Vincent Riquer
b718e34836 Edit CHANGELOG.md 2025-02-10 18:09:46 +00:00
Vincent Riquer
fd39c8bb16 Add CHANGELOG 2025-02-10 18:09:24 +00:00
Vincent Riquer
0b58d11c1e quickfix: parsing tags with soxi can hang on large embedded images 2025-02-10 18:41:32 +01:00
Vincent Riquer
d147cdc49c quickfix: help text indentation 2025-02-10 18:41:00 +01:00
Vincent Riquer
5032bb8739 Merge branch '8-feat-support-for-releasecountry-tag' into 'master'
Resolve "FEAT: support for releasecountry tag"

Closes #8 and #9

See merge request atom/AtOM!15
2025-02-10 00:52:01 +00:00
Vincent Riquer
979280c330 Resolve "FEAT: support for releasecountry tag"
Resolve "Opus (and maybe vorbis?) tags aren't actually read!"
2025-02-10 00:52:00 +00:00
Vincent Riquer
2cf968353f Ignore Makefile.in 2025-02-09 20:34:34 +01:00
44 changed files with 1073 additions and 621 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.ex
*.EX
trace.log
.vscode/
.vscode/
Makefile.in

34
CHANGELOG.md Normal file
View File

@ -0,0 +1,34 @@
# 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
### Bugs
* Tag reading hangs on vorbis files with embedded images.
* Recreate destination files on releasecountry tag change (bump database schema to 5).
# 1.0.1
## `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.
### Enhancements
* Copy releasecountry tag ("MusicBrainz Album Release Country" for MP3).
### Bugs
* Opus tags were not actually parsed due to an issue with the tag reader selector.
### Enhancements
* Fetch releasecountry tag from files
* Add `%{releasecountry}` placeholder in `rename`
* Add `-r` (show release country) to toys/createindex
# 1.0.0
Initial public release

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!
Here's what I have for my tests:
| Directory | Format | Frequency | Bitrate | Channels | FAT32 compat. | ASCII | Size |
| --------- | ------ | --------- | ------- | -------- | ------------- | ----- | ---- |
| 0-Full | Mixed | Mixed | Mixed | Mixed | No | No | 508G |
| 1-High | Opus | Same | 128 | Same | Yes | No | 101G |
| 2-Medium | Opus | Same | 64 | Same | Yes | No | 59G |
| 3-Small | Opus | Same | 32 | Same | Yes | No | 30G |
| 4-MP3 | MP3 | 44100 | 128 | 2 | Yes | Yes | 114G |
| Directory | Format | Sample rate | Bitrate | Channels | FAT32 compat. | ASCII | Size |
| --------- | ------ | ----------- | ------- | -------- | ------------- | ----- | ---- |
| 0-Full | Mixed | Mixed | Mixed | Mixed | No | No | 508G |
| 1-High | Opus | Same | 128 | Same | Yes | No | 101G |
| 2-Medium | Opus | Same | 64 | Same | Yes | No | 59G |
| 3-Small | Opus | Same | 32 | Same | Yes | No | 30G |
| 4-MP3 | MP3 | 44100 | 128 | 2 | Yes | Yes | 114G |
* URL: https://framagit.org/ScriptFanix/AtOM/
* URL: https://framagit.org/atom/AtOM/
* Author: Vincent Riquer <vincent+prog.atom@riquer.fr>
* Copyright/left: 2012-2013,2015,2025 Vincent Riquer - GPLv3

5
TODO
View File

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

254
atom
View File

@ -72,7 +72,7 @@ help() {
-c <file> Load configuration file <file>
-C Dump configuration and exit
-l <load> Override max-load
-f <workers> Use exactly <workers> child processes
-f <workers> Use exactly <workers> child processes
-T <seconds> override load-interval
-F <destination> Force re-generation of all files in
<destination>
@ -183,163 +183,7 @@ set +H
(( cfgdump )) && exit
# check sanity
if [ ! -d "$tempdir" ] && ! mkdir -p "$tempdir"
then
echo "[FATAL] Could not create temp directory $tempdir" >&2
(( sanityfail++ ))
fi
if [ ! -f "$database" ] && [ ! -d "${database%/*}" ] && ! mkdir -p "${database%/*}"
then
echo "[FATAL] Directory holding database file does not exist and could" \
"not be created" >&2
(( sanityfail++ ))
fi
if [ ! -d "$sourcepath" ]
then
echo "[FATAL] Source path $sourcepath does not exist or is not a directory" >&2
(( sanityfail++ ))
fi
if ! which sed >/dev/null
then
echo "[FATAL] Required tool sed is not installed or not in PATH
I never thought this would actually hit someone..." >&2
(( sanityfail++ ))
fi
if ! which sox >/dev/null
then
echo "[FATAL] Required tool sox is not installed or not in PATH" >&2
(( sanityfail++ ))
fi
if ! which ogginfo >/dev/null
then
echo "[WARNING] Tool ogginfo (from vorbis-tools) is not" \
"installed or not in PATH
WebM metadata disabled" >&2
disableogginfo=1
(( sanitywarn++ ))
fi
if ! which soxi >/dev/null
then
echo "[WARNING] Tool soxi (from sox) is not" \
"installed or not in PATH
Vorbis metadata disabled" >&2
disablesoxi=1
(( sanitywarn++ ))
fi
if (( oggencneeded )) && ! which oggenc >/dev/null
then
echo "[WARNING] Tool oggenc (from vorbis-tools) is not" \
"installed or not in PATH
Vorbis targets disabled" >&2
disableoggenc=1
(( sanitywarn++ ))
fi
if ! which opusinfo >/dev/null
then
echo "[WARNING] Tool opusinfo (from opus-tools) is not" \
"installed or not in PATH
Opus metadata disabled" >&2
disableopusinfo=1
(( sanitywarn++ ))
fi
if (( opusencneeded )) && ! which opusenc >/dev/null
then
echo "[WARNING] Tool opusenc (from opus-tools) is not" \
"installed or not in PATH
Opus targets disabled" >&2
disableopusenc=1
(( sanitywarn++ ))
fi
if ! which opusdec >/dev/null
then
echo "[WARNING] Tool opusdec (from opus-tools) is not" \
"installed or not in PATH
Opus support disabled" >&2
disableopusdec=1
(( sanitywarn++ ))
fi
if (( lameneeded )) && ! which lame >/dev/null
then
echo "[WARNING] Tool lame is not installed or not in PATH
MP3 targets disabled" >&2
disablelame=1
(( sanitywarn++ ))
fi
if ! which metaflac >/dev/null
then
echo "[WARNING] Tool metaflac (from FLAC) is not installed" \
"or not in PATH
FLAC metadata disabled" >&2
disableflac=1
(( sanitywarn++ ))
fi
if ! which mpcdec >/dev/null
then
echo "[WARNING] Tool mpcdec (from Musepack) is not" \
"installed or not in PATH
Musepack support disabled" >&2
disablempcdec=1
(( sanitywarn++ ))
fi
if ! which mkvextract >/dev/null
then
echo "[WARNING] Tool mkvextract (from MKVToolNix) is not" \
"installed or not in PATH
WebM metadata disabled
WebM support disabled" >&2
disablemkvextract=1
(( sanitywarn++ ))
fi
if ! which ffprobe >/dev/null
then
echo "[WARNING] Tool ffprobe (from FFmpeg) is not installed or not in PATH
Video metadata disabled
MPEG metadata disabled
MusePack metadata disabled
Unknown format metadata disabled" >&2
disableffprobe=1
(( sanitywarn++ ))
fi
if ! which ffmpeg >/dev/null
then
echo "[WARNING] Tool ffmpeg is not installed or not in PATH
Video support disabled" >&2
disablevideo=1
(( sanitywarn++ ))
fi
if (( textunidecodeneeded )) && ! perl -MText::Unidecode -e 'exit;' 2>/dev/null
then
echo "[WARNING] Perl module Text::Unidecode is not available
Renaming to ASCII-only disabled" >&2
unset destinationascii
destinationascii=0
textunidecodeneeded=0
(( sanitywarn++ ))
fi
if (( sanityfail ))
then
echo "
Sanity checks raised ${sanitywarn:-0} warnings, $sanityfail failures. Dying now." >&2
exit $ESANITY
elif (( sanitywarn ))
then
echo "
Sanity checks raised $sanitywarn warnings... Hit Control-C to abort." >&2
if ! (( cron ))
then
timeout=$(( sanitywarn * 10 ))
echo -n "Starting in $(printf %3i $timeout)" \
$'seconds...\b\b\b\b\b\b\b\b\b\b\b' >&2
while (( timeout ))
do
echo -n $'\b\b\b'"$(printf %3i $timeout)" >&2
sleep 1
(( timeout-- ))
done
echo -en "\r\033[K"
fi
fi
sanityCheck
openDatabase
for destination in "${destinations[@]}"
@ -554,20 +398,23 @@ echo '
mime_type_actions.mime_text,
destinations.name,
destination_files.id,
tags.depth,
tags.rate,
tags.channels,
tags.bitrate,
tags.genre,
tags.albumartist,
tags.year,
tags.album,
tags.disc,
tags.albumartist,
tags.artist,
tags.track,
tags.title,
tags.bitrate,
tags.channels,
tags.composer,
tags.performer
tags.depth,
tags.disc,
tags.genre,
tags.performer,
tags.rate,
tags.releasecountry,
tags.replaygain_alb,
tags.replaygain_trk,
tags.title,
tags.track,
tags.year
FROM source_files
INNER JOIN destination_files
ON source_files.id
@ -610,33 +457,39 @@ do
rest=${rest#*::AtOM:SQL:Sep::}
destfileid=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
bitdepth=${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::*}
album=${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::*}
bitrate=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
title=${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::}
rate=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
releasecountry=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
replaygain_alb=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
replaygain_trk=${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::*}
unset rest
case ${destinationformat["$destination"]} in
vorbis) (( disableoggenc )) && continue ;;
@ -648,7 +501,7 @@ do
getDestFile
for copy_ext in "${destinationcopyext[@]}"
do
if [[ $filename =~ '.*'"$copy_ext" ]]
if [[ $filename =~ '.*\.'"$copy_ext"'$' ]]
then
copied=1
break
@ -664,13 +517,13 @@ do
album \
albumartist \
artist \
bitdepth \
bitrate \
channels \
commandline \
composer \
copied \
decodetaskid \
depth \
destfileid \
destination \
disc \
@ -679,6 +532,9 @@ do
mimetype \
performer \
rate \
releasecountry \
replaygain_alb \
replaygain_trk \
rest \
sox_needed \
soxoptions_in \
@ -699,19 +555,20 @@ echo "Created ${count:-0} tasks for $filecount files ${togo:+($togo left) }(${co
concurrency=$(( maxload / 2 ))
(( concurrency )) || concurrency=1
active=0
concurrencychange=$(date +%s)
concurrencychange=$EPOCHSECONDS
starttime=$concurrencychange
taskcount=$count
remaining=$taskcount
failed=0
echo 'BEGIN TRANSACTION;' >&3
committime=$(date +%s)
committime=$EPOCHSECONDS
while (( (remaining || ${#workers[@]}) && ! quit ))
do
if (( $(date +%s) - committime >= 60 ))
timestamp=$EPOCHSECONDS
if (( $timestamp - committime >= 60 ))
then
echo $'COMMIT;\nBEGIN TRANSACTION;' >&3
committime=$(date +%s)
committime=$timestamp
fi
read humanload garbage < /proc/loadavg
load=${humanload%.*}
@ -721,16 +578,16 @@ do
else
if [ -z "$quit" ] \
&& (( ! pause )) \
&& (( $(date +%s)-concurrencychange >= loadinterval ))
&& (( timestamp - concurrencychange >= loadinterval ))
then
if (( concurrency > 1 )) \
&& (( load > maxload ))
then
concurrencychange=$(date +%s)
concurrencychange=$timestamp
(( --concurrency ))
elif (( load < maxload )) && (( active > concurrency - 1 ))
then
concurrencychange=$(date +%s)
concurrencychange=$timestamp
(( ++concurrency ))
fi
fi
@ -740,7 +597,7 @@ do
(( pause )) || master
if (( ran - failed ))
then
currenttime=$(date +%s)
currenttime=$timestamp
if (( pause ))
then
(( runtime = pausestart - starttime - pausedtime ))
@ -816,7 +673,7 @@ done
echo 'COMMIT;' >&3
unset count
endtime=$(date +%s)
endtime=$EPOCHSECONDS
(( elapsedseconds = endtime - starttime - pausedtime ))
(( days =
@ -952,6 +809,7 @@ do
tags.disc,
tags.genre,
tags.performer,
tags.releasecountry,
tags.title,
tags.track,
tags.year
@ -1020,6 +878,8 @@ do
rest=${rest#*::AtOM:SQL:Sep::}
performer=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
releasecountry=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
title=${rest%%::AtOM:SQL:Sep::*}
rest=${rest#*::AtOM:SQL:Sep::}
track=${rest%%::AtOM:SQL:Sep::*}

View File

@ -1,55 +1,186 @@
[general]
ionice 3
max-load 6
load-interval 30
temporary-directory %HOME%/.atom/tmp
database %HOME%/.atom/atom.db
debug 0
# 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
# * temporary-directory <directory>: String. Name speaks for itself: this is
# where FIFOs (for communicating with sqlite) and temporary WAVE files will
# be created. Note that debug logs (if enabled) will go there too.
temporary-directory /tmp/AtOM-user/
# * 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]
path /var/lib/mpd/music
skip /last
skip /lastfm
skip /zzz-atrier
# This section defines where are the files you want transcoded.
[Ogg]
path /mnt/Musique-OggQ2
format vorbis
quality 1
normalize yes
channels 2
frequency 44100
# * path <directory>: String. The root of your collection.
# Default: /var/lib/mpd/music
path /mnt/Musique
# * skip <directory>: String. Files in <directory> will be ignored. Note that
# <directory> can be any expression accepted by find.
skip /lost+found
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
# similar to "Audio file with ID3 version 2.4.0, unsynchronized frames"
copy_mime-type image/*
copy_mime-type text/*
# * skip_mime-type <mime-type>: Files with mime-type <mime-type> will not
# 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]
enabled 1
path /mnt/Musique-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
normalize yes
frequency 48000
copy_mime-type image/*
copy_mime-type text/*
[MP3]
path /mnt/Musique-mp3.test
enabled 1
path /mnt/Musique-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
# * 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
normalize yes
higher-than 128
# rename file, path unchanged
rename %{track}--%{artist}-%{title}
# change the whole filepath
#rename %{genre}/%{albumartist}/%{year}-%{album}/%{track}--%{artist}-%{title}
#rename %{genre}/%{albumartist}/%{year}-%{album}-%{releasecountry}/%{track}--%{artist}-%{title}
skip_mime-type image/*
skip_mime-type text/*
[asterisk]
enabled 1
path /mnt/Musique-asterisk
format vorbis
quality 0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
upgradedatabase_2_3() {
local data \
@ -11,4 +11,4 @@ upgradedatabase_2_3() {
Update destinations enabled 1 <<< "1 = 1"
Update atom version 3 <<<"1 = 1"
}
}

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
upgradedatabase_3_4() {
echo "Upgrading database to version 4... (backup is $database.bak_v3)"
cp "$database" "$database.bak_v3"
echo 'ALTER TABLE tags ADD COLUMN releasecountry TEXT;' >&3
Update atom version 4 <<<"1 = 1"
}

View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
upgradedatabase_4_5() {
echo "Upgrading database to version 5... (backup is $database.bak_v4)"
cp "$database" "$database.bak_v4"
echo 'DROP TRIGGER force_destination_update_on_tag_update;' >&3
echo '
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,
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 5 <<<"1 = 1"
}

View File

@ -0,0 +1,37 @@
#!/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"]})
soxoptions_out+=" -c ${destinationchannels["$destination"]}"
fi
if (( ${bitdepth:-0} > 16 ))
if (( ${depth:-0} > 16 ))
then
commandline+=(-b 16)
soxoptions_out+=" -b 16"

View File

@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
encodeFile::mp3() {
lameopts=(${ionice}lame --quiet)
lameopts=(${ionice}lame --quiet --noreplaygain)
lameopts+=(-v --abr ${destinationquality[$destination]})
[ -n "$album" ] && lameopts+=(--tl "$album" )
[ -n "$artist" ] && lameopts+=(--ta "$artist")
@ -11,6 +11,12 @@ encodeFile::mp3() {
[ -n "$albumartist" ] && lameopts+=(--tv TPE2="$albumartist")
[ -n "$composer" ] && lameopts+=(--tv TCOM="$composer")
[ -n "$performer" ] && lameopts+=(--tv TOPE="$performer")
[ -n "$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")
if (( ${destinationnoresample[$destination]:-0} == 1 ))
then

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
encodeFile::opus() {
opusencopts=(${ionice}opusenc --quiet)
opusencopts+=(--bitrate ${destinationquality[$destination]})
@ -11,6 +11,14 @@ encodeFile::opus() {
[ -n "$disc" ] && opusencopts+=(--comment "DISCNUMBER=$disc")
[ -n "$genre" ] && opusencopts+=(--comment "GENRE=$genre")
[ -n "$performer" ] && opusencopts+=(--comment "PERFORMER=$performer")
[ -n "$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 "$track" ] && opusencopts+=(--comment "TRACKNUMBER=${track%/*}")
[ -n "${track#*/}" ] && opusencopts+=(--comment "TRACKTOTAL=${track#*/}")

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
encodeFile::vorbis() {
oggencopts=(${ionice}oggenc -Q -q ${destinationquality[$destination]})
[ -n "$albumartist" ] && oggencopts+=(-c "ALBUMARTIST=$albumartist")
@ -8,6 +8,12 @@ encodeFile::vorbis() {
[ -n "$disc" ] && oggencopts+=(-c "DISCNUMBER=$disc")
[ -n "$genre" ] && oggencopts+=(-G "$genre")
[ -n "$performer" ] && oggencopts+=(-c "PERFORMER=$performer")
[ -n "$releasecountry" ] \
&& oggencopts+=(-c "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 "$track" ] && oggencopts+=(-N "$track")
[ -n "$year" ] && oggencopts+=(-d "$year")

View File

@ -10,6 +10,10 @@ getDestDir() {
[[ ${destinationrenamepath[$destination]} == \
*?([^[])%\{albumartist\}?([^\]])* ]] \
&& [ -n "$albumartist" ]
) || (
[[ ${destinationrenamepath[$destination]} == \
*?([^[])%\{releasecountry\}?([^\]])* ]] \
&& [ -n "$releasecountry" ]
) || (
[[ ${destinationrenamepath[$destination]} == \
*?([^[])%\{artist\}?([^\]])* ]] \
@ -44,6 +48,8 @@ getDestDir() {
read -r -u${toascii[0]} album
echo "$albumartist" >&${toascii[1]}
read -r -u${toascii[0]} albumartist
echo "$releasecountry" >&${toascii[1]}
read -r -u${toascii[0]} releasecountry
echo "$artist" >&${toascii[1]}
read -r -u${toascii[0]} artist
echo "$genre" >&${toascii[1]}
@ -61,6 +67,8 @@ getDestDir() {
destdir+="${destinationrenamepath[$destination]//?(\[)%\{album\}?(\])/$replace}"
replace=$(sanitizeFile "$albumartist" dir)
destdir="${destdir//?(\[)%\{albumartist\}?(\])/$replace}"
replace=$(sanitizeFile "$releasecountry" dir)
destdir="${destdir//?(\[)%\{releasecountry\}?(\])/$releasecountry}"
replace=$(sanitizeFile "$artist" dir)
destdir="${destdir//?(\[)%\{artist\}?(\])/$replace}"
replace=$(sanitizeFile "$genre" dir)

View File

@ -10,6 +10,10 @@ getDestFile() {
[[ ${destinationrename[$destination]} == \
*?([^[])%\{albumartist\}?([^\]])* ]] \
&& [ -n "$albumartist" ]
) || (
[[ ${destinationrenamepath[$destination]} == \
*?([^[])%\{releasecountry\}?([^\]])* ]] \
&& [ -n "$releasecountry" ]
) || (
[[ ${destinationrename[$destination]} == \
*?([^[])%\{artist\}?([^\]])* ]] \
@ -39,6 +43,7 @@ getDestFile() {
then
destfile="${destinationrename[$destination]//?(\[)%\{album\}?(\])/$album}"
destfile="${destfile//?(\[)%\{albumartist\}?(\])/$albumartist}"
destfile="${destfile//?(\[)%\{releasecountry\}?(\])/$releasecountry}"
destfile="${destfile//?(\[)%\{artist\}?(\])/$artist}"
destfile="${destfile//?(\[)%\{genre\}?(\])/$genre}"
destfile="${destfile//?(\[)%\{title\}?(\])/$title}"

View File

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

View File

@ -251,6 +251,7 @@ setupDestination() {
%{artist},
%{disc},
%{genre},
%{releasecountry},
%{title},
%{track},
%{year}.
@ -387,16 +388,16 @@ setupDestination() {
copiedmimes+=("${destinationcopymime["$destination"]%%|*}")
destinationcopymime["$destination"]="${destinationcopymime["$destination"]#*|}"
done
[ -n "${destinationcopymime["$destination"]}" ] \
[ -n "${destinationcopymime["$destination"]}" ] \
&& copiedmimes+=("${destinationcopymime["$destination"]}")
count=${#copiedmimes[@]}
unset destinationcopymime["$destination"]
for (( i=0 ; 1 ; i++ ))
do
read \
-e \
read \
-e \
${copiedmimes[i]+-i"${copiedmimes[i]}"} \
-p 'Copy mime-type: ' \
-p 'Copy mime-type: ' \
value
if [ -n "$value" ]
then
@ -409,6 +410,44 @@ setupDestination() {
fi
done
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
Channels (integer):

View File

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

View File

@ -1,55 +0,0 @@
#!/bin/bash
getInfosffmpeg_version='ffmpeg-6'
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)
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')
bitrate=$(gettag 'bit_rate')
bitdepth=$(gettag 'sample_fmt')
bitdepth=${bitdepth//[A-z]/}
if [[ $bitrate == N/A ]]
then
unset bitrate
else
bitrate=$((bitrate / 1000))
fi
}

View File

@ -1,48 +0,0 @@
#!/bin/bash
getInfosFLAC_version='FLAC-3'
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)
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"
)
}

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

@ -0,0 +1,54 @@
#!/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,8 +1,11 @@
#!/bin/bash
getInfosOpus_version='Opus-2'
#!/usr/bin/env bash
getInfosOpus_version='Opus-4'
tagreaders+=( "$getInfosOpus_version" )
getInfos::Opus() {
tagreader="$getInfosOpus_version"
local \
infos \
infos=$(
opusinfo "$sourcepath/$filename" \
| sed 's/\t//'
@ -14,6 +17,9 @@ getInfos::Opus() {
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)
@ -24,7 +30,9 @@ getInfos::Opus() {
year=$(gettag date)
infos="${infos//: /=}"
rate=$(gettag 'original sample rate'|head -n1)
rate=${rate% Hz}
channels=$(gettag channels|head -n1)
bitrate=$(gettag 'average bitrate')
bitrate=${bitrate%% kbit*}
bitrate=${bitrate%%.*}
}

75
lib/tags/getInfos::ffmpeg Normal file
View File

@ -0,0 +1,75 @@
#!/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,10 +1,14 @@
#!/bin/bash
getInfosSoxi_version='soxi-1'
#!/usr/bin/env bash
getInfosSoxi_version='soxi-3'
tagreaders+=( "$getInfosSoxi_version" )
getInfos::soxi() {
tagreader="$getInfosSoxi_version"
local \
infos \
infos=$(
soxi "$sourcepath/$filename"
soxi "$sourcepath/$filename" \
| grep -v METADATA_BLOCK_PICTURE
)
albumartist=$(gettag albumartist)
album=$(gettag album)
@ -13,6 +17,9 @@ getInfos::soxi() {
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)
@ -27,6 +34,6 @@ getInfos::soxi() {
bitrate=$(gettag 'bit rate')
bitrate=${bitrate%k}
bitrate=${bitrate%%.*}
bitdepth=$(gettag precision)
bitdepth=${bitdepth%-bit}
depth=$(gettag precision)
depth=${depth%-bit}
}

View File

@ -11,11 +11,15 @@ getTags() {
type=Opus
(( disableopusinfo )) && unset type
;;
'audio/ogg opus')
type=Opus
(( disableopusinfo )) && unset type
;;
application/ogg*)
type=soxi
(( disablesoxi )) && unset type
;;
audio/ogg)
audio/ogg*)
type=soxi
(( disablesoxi )) && unset type
;;

View File

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

View File

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

166
lib/tools/sanityChecks Normal file
View File

@ -0,0 +1,166 @@
#!/usr/bin/env bash
sanityCheck() {
if [ ! -d "$tempdir" ] && ! mkdir -p "$tempdir"
then
echo "[FATAL] Could not create temp directory $tempdir" >&2
(( sanityfail++ ))
fi
if [ ! -f "$database" ] && [ ! -d "${database%/*}" ] \
&& ! mkdir -p "${database%/*}"
then
echo "[FATAL] Directory holding database file does not exist"\
"and could not be created" >&2
(( sanityfail++ ))
fi
if [ ! -d "$sourcepath" ]
then
echo "[FATAL] Source path $sourcepath does not exist or is"\
"not a directory" >&2
(( sanityfail++ ))
fi
if ! which sed >/dev/null
then
echo "[FATAL] Required tool sed is not installed or not in PATH
I never thought this would actually hit someone..." >&2
(( sanityfail++ ))
fi
if ! which sox >/dev/null
then
echo "[FATAL] Required tool sox is not installed or not in"\
"PATH" >&2
(( sanityfail++ ))
fi
if ! which ogginfo >/dev/null
then
echo "[WARNING] Tool ogginfo (from vorbis-tools) is not"\
"installed or not in PATH
WebM metadata disabled" >&2
disableogginfo=1
(( sanitywarn++ ))
fi
if ! which soxi >/dev/null
then
echo "[WARNING] Tool soxi (from sox) is not" \
"installed or not in PATH
Vorbis metadata disabled" >&2
disablesoxi=1
(( sanitywarn++ ))
fi
if (( oggencneeded )) && ! which oggenc >/dev/null
then
echo "[WARNING] Tool oggenc (from vorbis-tools) is not" \
"installed or not in PATH
Vorbis targets disabled" >&2
disableoggenc=1
(( sanitywarn++ ))
fi
if ! which opusinfo >/dev/null
then
echo "[WARNING] Tool opusinfo (from opus-tools) is not" \
"installed or not in PATH
Opus metadata disabled" >&2
disableopusinfo=1
(( sanitywarn++ ))
fi
if (( opusencneeded )) && ! which opusenc >/dev/null
then
echo "[WARNING] Tool opusenc (from opus-tools) is not" \
"installed or not in PATH
Opus targets disabled" >&2
disableopusenc=1
(( sanitywarn++ ))
fi
if ! which opusdec >/dev/null
then
echo "[WARNING] Tool opusdec (from opus-tools) is not" \
"installed or not in PATH
Opus support disabled" >&2
disableopusdec=1
(( sanitywarn++ ))
fi
if (( lameneeded )) && ! which lame >/dev/null
then
echo "[WARNING] Tool lame is not installed or not in PATH
MP3 targets disabled" >&2
disablelame=1
(( sanitywarn++ ))
fi
if ! which metaflac >/dev/null
then
echo "[WARNING] Tool metaflac (from FLAC) is not installed"\
"or not in PATH
FLAC metadata disabled" >&2
disableflac=1
(( sanitywarn++ ))
fi
if ! which mpcdec >/dev/null
then
echo "[WARNING] Tool mpcdec (from Musepack) is not" \
"installed or not in PATH
Musepack support disabled" >&2
disablempcdec=1
(( sanitywarn++ ))
fi
if ! which mkvextract >/dev/null
then
echo "[WARNING] Tool mkvextract (from MKVToolNix) is not"\
"installed or not in PATH
WebM metadata disabled
WebM support disabled" >&2
disablemkvextract=1
(( sanitywarn++ ))
fi
if ! which ffprobe >/dev/null
then
echo "[WARNING] Tool ffprobe (from FFmpeg) is not installed"\
"or not in PATH
Video metadata disabled
MPEG metadata disabled
MusePack metadata disabled
Unknown format metadata disabled" >&2
disableffprobe=1
(( sanitywarn++ ))
fi
if ! which ffmpeg >/dev/null
then
echo "[WARNING] Tool ffmpeg is not installed or not in PATH
Video support disabled" >&2
disablevideo=1
(( sanitywarn++ ))
fi
if (( textunidecodeneeded )) && ! perl -MText::Unidecode -e 'exit;' 2>/dev/null
then
echo "[WARNING] Perl module Text::Unidecode is not available
Renaming to ASCII-only disabled" >&2
unset destinationascii
destinationascii=0
textunidecodeneeded=0
(( sanitywarn++ ))
fi
if (( sanityfail ))
then
echo "
Sanity checks raised ${sanitywarn:-0} warnings, $sanityfail failures. Dying now." >&2
exit $ESANITY
elif (( sanitywarn ))
then
echo "
Sanity checks raised $sanitywarn warnings... Hit Control-C to abort." >&2
if ! (( cron ))
then
timeout=$(( sanitywarn * 10 ))
echo -n "Starting in $(printf %3i $timeout)" \
$'seconds...\b\b\b\b\b\b\b\b\b\b\b' >&2
while (( timeout ))
do
echo -n $'\b\b\b'"$(printf %3i $timeout)" >&2
sleep 1
(( timeout-- ))
done
echo -en "\r\033[K"
fi
fi
}
# vim:set ts=8 sw=8:

View File

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

View File

@ -58,6 +58,9 @@ CREATE TABLE IF NOT EXISTS tags (
title TEXT,
composer TEXT,
performer TEXT,
releasecountry TEXT,
replaygain_alb TEXT,
replaygain_trk TEXT,
depth INTEGER,
rate INTEGER,
channels INTEGER,
@ -129,10 +132,13 @@ CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
title,
composer,
performer,
releasecountry,
replaygain_alb,
replaygain_trk,
rate,
channels,
bitrate,
bitdepth
depth
ON tags
BEGIN
UPDATE destination_files SET last_change=0

View File

@ -62,6 +62,7 @@ done
getConfig
sanityCheck
openDatabase
(( update )) && getFiles

View File

@ -58,7 +58,7 @@ do
done
getConfig
sanityCheck
openDatabase
sourcepath=''

View File

@ -59,7 +59,7 @@ do
done
getConfig
sanityCheck
openDatabase
echo 'SELECT id,filename FROM destination_files WHERE filename IS NOT NULL;' >&3

View File

@ -59,7 +59,7 @@ do
done
getConfig
sanityCheck
openDatabase
checkwanted() {

View File

@ -38,7 +38,7 @@ LC_ALL=C
shopt -s extglob
source ./share/id3genres
source "$SHAREDIR"/id3genres
for function in "$LIBDIR"/*/*
do
@ -73,6 +73,7 @@ do
'-M') show+=(types) ;;
'-N') show+=(tracktotals) ;;
'-p') show+=(performers) ;;
'-r') show+=(releasecountries) ;;
'-s') show+=(rates) ;;
'-S') show+=(size)
length[count]=5 ;;
@ -121,6 +122,7 @@ done
-d Disc
-g Genre
-p Performer
-r Release Country
-N Track total
-t Title
-y Year
@ -137,7 +139,7 @@ done
}
getConfig
sanityCheck
openDatabase
columns="${show[@]//*/-}"
@ -280,17 +282,17 @@ fi
cat <<-EOBrag
# Generated by AtOM's createindex toy.
# https://gitorious.org/atom
# (C) 2012-2013 Vincent Riquer (GPL-3)
# https://framagit.org/atom/AtOM/
# (C) 2012-2025 Vincent Riquer (GPL-3)
#
# $0 $args
#
# Last database update: $(date -d @$lastupdate +'%x %X')
# Last database update: $(printf "%(%x %X)T" "$lastupdate")
EOBrag
printDate() {
date -d"@$1" +"${timeformat:-%x %X}"
printf "%("${timeformat:-%x %X}")T" "$1"
}
for index in ${!show[@]}
@ -312,6 +314,7 @@ do
oldtimestamp) info='Last modified' ;;
types) info='Format' ;;
performers) info='Performer' ;;
releasecountries) info='Country' ;;
rates) info='Sample rate' ;;
titles) info='Title' ;;
tracktotals) info='Track total' ;;
@ -345,6 +348,7 @@ SELECT
tags.disc,
tags.genre,
tags.performer,
tags.releasecountry,
tags.title,
tags.track,
tags.year,
@ -403,6 +407,8 @@ do
rest="${rest#*::AtOM:SQL:Sep::}"
performer="${rest%%::AtOM:SQL:Sep::*}"
rest="${rest#*::AtOM:SQL:Sep::}"
releasecountry="${rest%%::AtOM:SQL:Sep::*}"
rest="${rest#*::AtOM:SQL:Sep::}"
title="${rest%%::AtOM:SQL:Sep::*}"
rest="${rest#*::AtOM:SQL:Sep::}"
track="${rest%%::AtOM:SQL:Sep::*}"
@ -530,6 +536,13 @@ do
[ -n "$performer" ] \
&& performers+="${performers+,}$performer"
fi
if ! [[ $releasecountries =~ $expr1"$releasecountry"$expr2 ]]
then
[ -z "$releasecountries" ] \
&& unset releasecountries
[ -n "$releasecountry" ] \
&& releasecountries+="${releasecountries+,}$releasecountry"
fi
if ! [[ $titles =~ $expr1"$title"$expr2 ]]
then
[ -z "$titles" ] \
@ -556,10 +569,10 @@ do
then
printline
fi
unset bitrates
unset bitrates depths rates
channelss="$channels"
rates="$rate"
depths="$depth"
(( rate )) && rates="$rate"
(( depth )) && depths="$depth"
types="$type"
albumartists="$albumartist"
albums="$album"
@ -568,6 +581,7 @@ do
discs="$disc"
genres="$genre"
performers="$performer"
releasecountries="$releasecountry"
titles="$title"
tracktotals="$tracktotal"
years="$year"

View File

@ -75,7 +75,7 @@ do
done
getConfig
sanityCheck
openDatabase
if (( update ))

View File

@ -94,7 +94,7 @@ done
}
getConfig
sanityCheck
openDatabase
if (( update ))