From 7abfcab9174cf1703aead2bf5315b120c2d4dda2 Mon Sep 17 00:00:00 2001 From: "Arnaud G. GIBERT" Date: Sat, 11 Apr 2026 17:15:06 +0200 Subject: [PATCH] - Add SPEC file, - Add bash_completion, - Migrate album_convert, album_merge & album_name_fix commands. --- SPECS/music_tools.spec | 129 ++++++ bin/album_convert | 161 +++++--- bin/album_merge | 132 +++--- bin/album_name_fix | 140 ++++--- etc/bash_completion.d/album_convert | 48 +++ etc/bash_completion.d/album_merge | 53 +++ etc/bash_completion.d/album_name_fix | 56 +++ usr/lib/rx3/music.bash | 597 --------------------------- 8 files changed, 553 insertions(+), 763 deletions(-) create mode 100644 SPECS/music_tools.spec create mode 100644 etc/bash_completion.d/album_convert create mode 100644 etc/bash_completion.d/album_merge create mode 100644 etc/bash_completion.d/album_name_fix delete mode 100644 usr/lib/rx3/music.bash diff --git a/SPECS/music_tools.spec b/SPECS/music_tools.spec new file mode 100644 index 0000000..ae43f72 --- /dev/null +++ b/SPECS/music_tools.spec @@ -0,0 +1,129 @@ +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Music Tools +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- + + + +%define name music_tools + +%define version 1.0.0 +%define release %mkrel 1rx3 + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Package +#----------------------------------------------------------------------------------------------------------------------------------- + +Name: %{name} +Version: %{version} +Release: %{release} +Summary: Rx3 Music Tools + +License: GPL 3.0 +URL: https://git.rx3.org/gitea/rx3/%{name} +Group: System + +Distribution: Rx3 Free Software +Vendor: Rx3 +Packager: Arnaud G. GIBERT + +BuildArch: noarch + +Source0: https://git.rx3.org/gitea/rx3/%{name}/archive/%{name}-%{version}.tar.gz + + + +%description +These tools are used to manage the Rx3 music repository. + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Prep +#----------------------------------------------------------------------------------------------------------------------------------- + +%prep +%autosetup -p1 -n %{name} + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Build +#----------------------------------------------------------------------------------------------------------------------------------- + +%build + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Install +#----------------------------------------------------------------------------------------------------------------------------------- + +%install +# Bash completion +%{__mkdir_p} %{buildroot}%{_sysconfdir}/bash_completion.d +cp etc/bash_completion.d/* %{buildroot}%{_sysconfdir}/bash_completion.d + +# Lib +%{__mkdir_p} %{buildroot}%{_prefix}/lib/rx3 +cp usr/lib/rx3/*.bash %{buildroot}%{_prefix}/lib/rx3 + +# Bin +%{__mkdir_p} %{buildroot}%{_bindir} +cp bin/* %{buildroot}%{_bindir} + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Files +#----------------------------------------------------------------------------------------------------------------------------------- + +%files +%doc ReadMe.txt ReleaseNotes.txt ToDo.txt +%license COPYING COPYING.LESSER GNU_GPL-3.0.txt GNU_LGPL-3.0.txt GNU_FDL-1.3.txt +%defattr(644,root,root) + %{_sysconfdir}/bash_completion.d/* + %{_prefix}/lib/rx3/* +%attr(0755,root,root) %{_bindir}/* + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# ChangeLog +#----------------------------------------------------------------------------------------------------------------------------------- + +%changelog +* Sat Apr 11 2026 Arnaud G. GIBERT - 1.0.0-1rx3.mga9 +- Initial release diff --git a/bin/album_convert b/bin/album_convert index a19d5b7..a75db2f 100755 --- a/bin/album_convert +++ b/bin/album_convert @@ -1,103 +1,138 @@ #!/bin/bash +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Convert +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- + + +#----------------------------------------------------------------------------------------------------------------------------------- # Includes #----------------------------------------------------------------------------------------------------------------------------------- -. /usr/global/lib/music.bash +: "${RX3_LIB_DIR:=/usr/lib/rx3}" +. "${RX3_LIB_DIR}/music_tools.bash" -# System Constants +#----------------------------------------------------------------------------------------------------------------------------------- +# Global Variables #----------------------------------------------------------------------------------------------------------------------------------- - AC_NAME="album_convert" -AC_VERSION="$Name: album_convert-1_0_0-1 $" +declare -g VERSION="1.0.0" +declare -g NAME="album_convert" +declare -g HELP="usage: [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] [-r | --resample] [-d | --downsampled_tag] " + +declare -g RESAMPLE="FALSE" +declare -g DSTAG="FLASE" +declare -g SOURCE_DIR="" +declare -g TARGET_DIR="" + +declare -g MODE="DEFAULT" +declare -g VERBOSE="FALSE" +declare -g DRY_RUN="FALSE" -# Print Version +#----------------------------------------------------------------------------------------------------------------------------------- +# Version Print #----------------------------------------------------------------------------------------------------------------------------------- -function version_print() +ac_version_print() { - echo ${AC_VERSION} | sed -e 's/.*: //' -e 's/-/ /' -e 's/_/\./g' -e 's/\$$//' + version_print } -# Prin Help +#----------------------------------------------------------------------------------------------------------------------------------- +# Help Print #----------------------------------------------------------------------------------------------------------------------------------- -function help_print() +ac_help_print() { - echo "${AC_NAME} [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] [-r | --resample] [-d | --downsampled_tag] []" + ac_version_print + help_print } +#----------------------------------------------------------------------------------------------------------------------------------- # Arg Parse #----------------------------------------------------------------------------------------------------------------------------------- -function args_parse() +ac_args_parse() { - mode="default" - verbose="false" - resample="false" - dstag="flase" - source_dir="" - target_dir="" - - tmp_args=$(getopt -o ThVvrd --long test,help,version,verbose,resample,downsampled_tag -n "${AC_NAME}" -- "$@") + tmp_args=$(getopt -o ThVvrd --long test,help,version,verbose,resample,downsampled_tag -n "${NAME}" -- "$@") if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "${tmp_args}" - while true ; do + while true + do case "$1" in # Options # Mode switches - -T|--test) mode="test"; shift;; - -h|--help) mode="exit"; help_print; shift;; - -V|--version) mode="exit"; version_print; shift;; + -T|--test) MODE="TEST"; shift;; + -h|--help) MODE="EXIT"; ac_help_print; shift;; + -V|--version) MODE="EXIT"; ac_version_print; shift;; # Global options - -v|--verbose) verbose="true"; shift;; - -r|--resample) resample="true"; shift;; - -d|--downsampled_tag) dstag="true"; shift;; + -v|--verbose) VERBOSE="TRUE"; shift;; + -r|--resample) RESAMPLE="TRUE"; shift;; + -d|--downsampled_tag) DSTAG="TRUE"; shift;; # - --) shift; break;; + --) shift; break;; *) echo "args_parse internal error [$1] !"; exit 1;; esac done - if [[ "${mode}" != "exit" ]] + if [[ "${MODE}" != "EXIT" ]] then if [[ "${#}" != "2" ]] then if [[ "${#}" -lt "2" ]] then - echo "Not enough args!" + echo_error "Not enough args!" else - echo "Too many args!" + echo_error "Too many args!" fi - mode="exit" - help_print + MODE="EXIT" + ac_help_print else - source_dir="$1" - target_dir="$2" + SOURCE_DIR="$1" + TARGET_DIR="$2" fi fi } @@ -106,80 +141,84 @@ function args_parse() +#----------------------------------------------------------------------------------------------------------------------------------- # Main #----------------------------------------------------------------------------------------------------------------------------------- -args_parse "$@" +ac_args_parse "$@" -if [[ "${mode}" == "exit" ]] + + +if [[ "${MODE}" == "EXIT" ]] then exit 0 else - if [[ "${mode}" == "test" ]] + if [[ "${MODE}" == "TEST" ]] then - dry_run=true - else - dry_run=false + DRY_RUN="TRUE" fi fi -if [[ "${resample}" == "true" ]] +if [[ "${RESAMPLE}" == "TRUE" ]] then - resample_flags="-af \"aresample=out_sample_fmt=s16:out_sample_rate=44100\"" + resample_flags="-af aresample=out_sample_fmt=s16:out_sample_rate=44100" else resample_flags="" fi -echo "mode: [${mode}] verbose: [${verbose}] resample : [${resample}] downsampled_tag : [${dstag}] source_dir: [${source_dir}] target_dir: [${target_dir}]" 1>&2 +echo_error "${NAME}: Mode: [${MODE}] Verbose: [${VERBOSE}] Resample : [${RESAMPLE}] DownSampled_Tag : [${DSTAG}] Source_Dir: [${SOURCE_DIR}] Target_Dir: [${TARGET_DIR}]" -if [[ ! -d "${target_dir}" ]] +if [[ ! -d "${TARGET_DIR}" ]] then - echo "Target directory doesn't exit !" + echo_error "Target directory doesn't exit !" exit -1 fi -for file in "${source_dir}"/*@(.flac|.ogg|.mp3|.m4a|.ape|.wav) +for file in "${SOURCE_DIR}"/*@(.flac|.ogg|.mp3|.m4a|.ape|.wav) do id="$(basename "${file}" | sed -e "s/-.*//")" - target_file="${target_dir}/${prefix}$(basename "${file}" | sed -e 's/\.[^.]*$//').flac" + target_file="${TARGET_DIR}/$(basename "${file}" | sed -e 's/\.[^.]*$//').flac" - cmd="ffmpeg -i \"${file}\" -compression_level 12 ${resample_flags} \"${target_file}\"" - exec_cmd "${cmd}" + cmd_exec ffmpeg -i "${file}" -compression_level 12 ${resample_flags} "${target_file}" done - -if [[ ${resample} == "true" ]] +set -x +if [[ "${RESAMPLE}" == "TRUE" ]] then - for file in "${target_dir}"/*.flac + for file in "${TARGET_DIR}"/*.flac do - if [[ "${dstag}" == "true" ]] + if [[ "${DSTAG}" == "TRUE" ]] then tag="DESCRIPTION" - value="$(tag_read "${file}" "${tag}")" + value="$(mt_tag_read "${file}" "${tag}")" if [[ "$( echo "${value}" | grep "Downsampled")" == "" ]] then value="${value}\nDownsampled" - tag_delete "${file}" "${tag}" - tag_write "${file}" "${tag}" "${value}" + mt_tag_delete "${file}" "${tag}" + mt_tag_write "${file}" "${tag}" "${value}" fi fi for tag in "ALBUM" "TITLE" do - value="$(tag_read "${file}" "${tag}")" + value="$(mt_tag_read "${file}" "${tag}")" new_value="$(echo ${value} | sed -e 's/ - HD$//')" if [[ "${value}" != "${new_value}" ]] then - tag_delete "${file}" "${tag}" - tag_write "${file}" "${tag}" "${new_value}" + mt_tag_delete "${file}" "${tag}" + mt_tag_write "${file}" "${tag}" "${new_value}" fi done - cmd="mv \"${file}\" \"${file/-hd.flac/.flac}\"" - exec_cmd "${cmd}" + if [[ "${file}" != "${file/-hd.flac/.flac}" ]] + then + cmd_exec mv "${file}" "${file/-hd.flac/.flac}" + else + echo_error "No '-hd' renmaming needed..." + fi done fi diff --git a/bin/album_merge b/bin/album_merge index 69945bd..1d612b9 100755 --- a/bin/album_merge +++ b/bin/album_merge @@ -1,79 +1,113 @@ #!/bin/bash +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Convert +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- + + +#----------------------------------------------------------------------------------------------------------------------------------- # Includes #----------------------------------------------------------------------------------------------------------------------------------- -. /usr/global/lib/music.bash +: "${RX3_LIB_DIR:=/usr/lib/rx3}" +. "${RX3_LIB_DIR}/music_tools.bash" -# System Constants +#----------------------------------------------------------------------------------------------------------------------------------- +# Global Variables #----------------------------------------------------------------------------------------------------------------------------------- - AM_NAME="album_merge" -AM_VERSION="$Name: album_merge-1_0_0-1 $" +declare -g VERSION="1.0.0" +declare -g NAME="album_merge" +declare -g HELP="usage: [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] " + +declare -g SOURCE_DIR="" +declare -g TARGET_DIR="" +declare -g ALBUM_NAME="" +declare -g PREFIX="" + +declare -g MODE="DEFAULT" +declare -g VERBOSE="FALSE" +declare -g DRY_RUN="FALSE" -# Print Version +#----------------------------------------------------------------------------------------------------------------------------------- +# Version Print #----------------------------------------------------------------------------------------------------------------------------------- -function version_print() +am_version_print() { - echo ${AM_VERSION} | sed -e 's/.*: //' -e 's/-/ /' -e 's/_/\./g' -e 's/\$$//' + version_print } -# Prin Help +#----------------------------------------------------------------------------------------------------------------------------------- +# Help Print #----------------------------------------------------------------------------------------------------------------------------------- -function help_print() +am_help_print() { - echo "${AM_NAME} [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] " - + am_version_print + help_print } +#----------------------------------------------------------------------------------------------------------------------------------- # Arg Parse #----------------------------------------------------------------------------------------------------------------------------------- -function args_parse() +am_args_parse() { - mode="default" - verbose="false" - source_dir="" - target_dir="" - album_name="" - prefix="" - - tmp_args=$(getopt -o ThVv --long test,help,version,verbose -n "${AM_NAME}" -- "$@") + tmp_args=$(getopt -o ThVv --long test,help,version,verbose -n "${NAME}" -- "$@") if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "${tmp_args}" - while true ; do + while true + do case "$1" in # Options # Mode switches - -T|--test) mode="test"; shift;; - -h|--help) mode="exit"; help_print; shift;; - -V|--version) mode="exit"; version_print; shift;; + -T|--test) MODE="TEST"; shift;; + -h|--help) MODE="EXIT"; am_help_print; shift;; + -V|--version) MODE="EXIT"; am_version_print; shift;; # Global options - -v|--verbose) verbose="true"; shift;; + -v|--verbose) VERBOSE="TRUE"; shift;; # --) shift; break;; @@ -81,24 +115,24 @@ function args_parse() esac done - if [[ "${mode}" != "exit" ]] + if [[ "${MODE}" != "EXIT" ]] then if [[ "${#}" != "4" ]] then if [[ "${#}" -lt "4" ]] then - echo "Not enough args!" + echo_error "Not enough args!" else - echo "Too many args!" + echo_error "Too many args!" fi - mode="exit" - help_print + MODE="EXIT" + am_help_print else - source_dir="$1" - target_dir="$2" - album_name="$3" - prefix="$4" + SOURCE_DIR="$1" + TARGET_DIR="$2" + ALBUM_NAME="$3" + PREFIX="$4" fi fi } @@ -107,39 +141,37 @@ function args_parse() +#----------------------------------------------------------------------------------------------------------------------------------- # Main #----------------------------------------------------------------------------------------------------------------------------------- -shopt -s extglob +am_args_parse "$@" -args_parse "$@" -if [[ ${mode} == "exit" ]] + +if [[ ${MODE} == "EXIT" ]] then exit 0 else - if [[ ${mode} == "test" ]] + if [[ ${MODE} == "TEST" ]] then - dry_run=true - else - dry_run=false + DRY_RUN="TRUE" fi fi -echo "mode: [${mode}] verbose: [${verbose}] source_dir: [${source_dir}] target_dir: [${target_dir}] album_name: [${album_name}] prefix: [${prefix}]" 1>&2 +echo_error "${NAME}: Mode: [${MODE}] Verbose: [${VERBOSE}] Source_Dir: [${SOURCE_DIR}] Target_Dir: [${TARGET_DIR}] Album_Name: [${ALBUM_NAME}] Prefix: [${PREFIX}]" -for file in "${source_dir}"/*@(.flac|.mp3) +for file in "${SOURCE_DIR}"/*@(.flac|.mp3) do id="$(basename $file | sed -e "s/-.*//")" - target_file="${target_dir}/${prefix}$(basename $file)" + target_file="${TARGET_DIR}/${PREFIX}$(basename $file)" - cmd="cp \"${file}\" \"${target_file}\"" - exec_cmd "${cmd}" + cmd_exec cp "${file}" "${target_file}" - tag_delete "${target_file}" "ALBUM" - tag_write "${target_file}" "ALBUM" "${album_name}" - tag_delete "${target_file}" "TRACKNUMBER" - tag_write "${target_file}" "TRACKNUMBER" "${prefix}${id}" + mt_tag_delete "${target_file}" "ALBUM" + mt_tag_write "${target_file}" "ALBUM" "${ALBUM_NAME}" + mt_tag_delete "${target_file}" "TRACKNUMBER" + mt_tag_write "${target_file}" "TRACKNUMBER" "${PREFIX}${id}" done diff --git a/bin/album_name_fix b/bin/album_name_fix index a126806..3892909 100755 --- a/bin/album_name_fix +++ b/bin/album_name_fix @@ -1,80 +1,120 @@ #!/bin/bash - -. /usr/global/lib/music.bash - - - - - -# System Constants +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Name Fix +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# #----------------------------------------------------------------------------------------------------------------------------------- -ANF_VERSION="$Name: album_name_fix-1_0_0-1 $" - - - -# Print Version +#----------------------------------------------------------------------------------------------------------------------------------- +# Includes #----------------------------------------------------------------------------------------------------------------------------------- -function version_print() +: "${RX3_LIB_DIR:=/usr/lib/rx3}" +. "${RX3_LIB_DIR}/music_tools.bash" + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Global Variables +#----------------------------------------------------------------------------------------------------------------------------------- + +declare -g VERSION="1.0.0" +declare -g NAME="album_name_fix " +declare -g HELP="usage: [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] [-a ] [-p|--music_pattern ] [-s|--sed_substitute_pattern ]" + +declare -g ALBUM_DIR="." +declare -g MUSIC_PATTERN="." +declare -g SSP="" + +declare -g MODE="DEFAULT" +declare -g VERBOSE="FALSE" +declare -g DRY_RUN="FALSE" + + + + + +#----------------------------------------------------------------------------------------------------------------------------------- +# Version Print +#----------------------------------------------------------------------------------------------------------------------------------- + +anf_version_print() { - echo ${ANF_VERSION} | sed -e 's/.*: //' -e 's/-/ /' -e 's/_/\./g' -e 's/\$$//' + version_print } -# Prin Help +#----------------------------------------------------------------------------------------------------------------------------------- +# Help Print #----------------------------------------------------------------------------------------------------------------------------------- -function help_print() +anf_help_print() { - echo "album_name_fix [-h | --help] | [-V | --version] | [-T | --test] [-v | --verbose] [-a ] [-p|--music_pattern ] [-s|--sed_substitute_pattern ]" + anf_version_print + help_print } +#----------------------------------------------------------------------------------------------------------------------------------- # Arg Parse #----------------------------------------------------------------------------------------------------------------------------------- -function args_parse() +anf_args_parse() { - mode="default" - verbose="false" - album_dir="." - music_pattern="." - - tmp_args=$(getopt -o a:p:s:ThVv --long album_dir:,music_pattern:,sed_substitute_pattern:,test,help,version,verbose -n 'album_name_fix' -- "$@") + tmp_args=$(getopt -o a:p:s:ThVv --long album_dir:,music_pattern:,sed_substitute_pattern:,test,help,version,verbose -n "${NAME}" -- "$@") if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "${tmp_args}" - while true ; do + while true + do case "$1" in # Path options - -a|--album_dir) shift; album_dir="$1"; shift;; + -a|--album_dir) shift; ALBUM_DIR="$1"; shift;; # Options - -p|--music_pattern) shift; music_pattern="$1"; shift;; - -s|--sed_substitute_pattern) shift; ssp="$1"; shift;; + -p|--music_pattern) shift; MUSIC_PATTERN="$1"; shift;; + -s|--sed_substitute_pattern) shift; SSP="$1"; shift;; # Mode switches - -T|--test) mode="test"; shift;; - -h|--help) mode="exit"; help_print; shift;; - -V|--version) mode="exit"; version_print; shift;; + -T|--test) MODE="TEST"; shift;; + -h|--help) MODE="EXIT"; anf_help_print; shift;; + -V|--version) MODE="EXIT"; anf_version_print; shift;; # Global options - -v|--verbose) verbose="true"; shift;; + -v|--verbose) VERBOSE="TRUE"; shift;; # - --) shift; break;; + --) shift; break;; *) echo "args_parse internal error [$1] !"; exit 1;; esac done @@ -84,52 +124,42 @@ function args_parse() +#----------------------------------------------------------------------------------------------------------------------------------- # Main #----------------------------------------------------------------------------------------------------------------------------------- -shopt -s extglob - -args_parse "$@" +anf_args_parse "$@" -if [[ ${mode} == "exit" ]] +if [[ ${MODE} == "EXIT" ]] then exit 0 else - if [[ ${mode} == "test" ]] + if [[ ${MODE} == "TEST" ]] then - dry_run=true - else - dry_run=false + DRY_RUN="TRUE" fi fi -echo "mode: [${mode}] verbose: [${verbose}] album_dir: [${album_dir}] music_pattern: [${music_pattern}] sed_substitue_pattern: [${ssp}]" 1>&2 +echo_error "${NAME}: Mode: [${MODE}] Verbose: [${VERBOSE}] Album_Dir: [${ALBUM_DIR}] Music_Pattern: [${MUSIC_PATTERN}] Sed_Substitue_Pattern: [${SSP}]" -cd "${album_dir}" +cd "${ALBUM_DIR}" IFS="\n" -find . -maxdepth 1 -name '*.flac' -o -name '*.FLAC' -o -name '*.ogg' -o -name '*.OGG' -o -name '*.mp3' -o -name '*.MP3' -o -name '*.m4a' -o -name '*.M4A' -o -name '*.ape' -o -name '*.APE' -o -name '*.wav' -o -name '*.WAV' -o -name '*.mp4' -o -name '*.MP4' -o -name '*.mkv' -o -name '*.MKV' | sed -e 's/^.\///' | grep -e "${music_pattern}" | sort | +find . -maxdepth 1 -name '*.flac' -o -name '*.FLAC' -o -name '*.ogg' -o -name '*.OGG' -o -name '*.mp3' -o -name '*.MP3' -o -name '*.m4a' -o -name '*.M4A' -o -name '*.ape' -o -name '*.APE' -o -name '*.wav' -o -name '*.WAV' -o -name '*.mp4' -o -name '*.MP4' -o -name '*.mkv' -o -name '*.MKV' | sed -e 's/^.\///' | grep -e "${MUSIC_PATTERN}" | sort | while read track_file do IFS=" " - new_track_file="$(fix_file_name "${track_file}" "${ssp}")" + new_track_file="$(mt_fix_file_name "${track_file}" "${SSP}")" if [[ "${new_track_file}" != "${track_file}" ]] then echo "Moving '${track_file}' into '${new_track_file}'..." - if [[ "${dry_run}" != "true" ]] - then - mv -- "${track_file}" "${new_track_file}" - else - if [[ "${verbose}" == "true" ]] - then - echo mv -- "${track_file}" "${new_track_file}" - fi - fi + + cmd_exec mv -- "${track_file}" "${new_track_file}" else echo "Skiping '${track_file}'..." fi diff --git a/etc/bash_completion.d/album_convert b/etc/bash_completion.d/album_convert new file mode 100644 index 0000000..245fab0 --- /dev/null +++ b/etc/bash_completion.d/album_convert @@ -0,0 +1,48 @@ +#!/bin/bash +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Convert +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- +# -*- mode: shell; sh-basic-offset: 4; indent-tabs-mode: nil; -*- + + + +_album_convert_completion() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="-h --help -V --version -T --test -v --verbose -r --resample -d --downsampled_tag" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + # Handle directory completion for source_dir and target_dir + if [[ ${COMP_CWORD} -eq 1 ]] || [[ ${prev} != -* && ${COMP_CWORD} -eq 2 ]]; then + COMPREPLY=( $(compgen -d -- "${cur}") ) + fi +} + + + +complete -F _album_convert_completion album_convert diff --git a/etc/bash_completion.d/album_merge b/etc/bash_completion.d/album_merge new file mode 100644 index 0000000..461ee5d --- /dev/null +++ b/etc/bash_completion.d/album_merge @@ -0,0 +1,53 @@ +#!/bin/bash +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Merge +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- +# -*- mode: shell; sh-basic-offset: 4; indent-tabs-mode: nil; -*- + + + +_album_merge_completion() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="-h --help -V --version -T --test -v --verbose" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + # Handle directory and argument completion + case ${COMP_CWORD} in + 1|2) + COMPREPLY=( $(compgen -d -- "${cur}") ) + ;; + 3|4) + COMPREPLY=() + ;; + esac +} + + + +complete -F _album_merge_completion album_merge diff --git a/etc/bash_completion.d/album_name_fix b/etc/bash_completion.d/album_name_fix new file mode 100644 index 0000000..47c6eab --- /dev/null +++ b/etc/bash_completion.d/album_name_fix @@ -0,0 +1,56 @@ +#!/bin/bash +#----------------------------------------------------------------------------------------------------------------------------------- +# +# Album Name Fix +# +# Copyright (C) 2016-2026 Arnaud G. GIBERT +# mailto:arnaud@rx3.net +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see +# . +# +#----------------------------------------------------------------------------------------------------------------------------------- +# -*- mode: shell; sh-basic-offset: 4; indent-tabs-mode: nil; -*- + + + +_album_name_fix_completion() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="-h --help -V --version -T --test -v --verbose -a --music_pattern -p --sed_substitute_pattern -s" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + # Handle argument completion for -a, -p, -s + case "${prev}" in + -a|--album_dir) + COMPREPLY=( $(compgen -d -- "${cur}") ) + ;; + -p|--music_pattern) + COMPREPLY=() + ;; + -s|--sed_substitute_pattern) + COMPREPLY=() + ;; + esac +} + + + +complete -F _album_name_fix_completion album_name_fix diff --git a/usr/lib/rx3/music.bash b/usr/lib/rx3/music.bash deleted file mode 100644 index 875ce7b..0000000 --- a/usr/lib/rx3/music.bash +++ /dev/null @@ -1,597 +0,0 @@ -#!/bin/bash - -if [[ "${MUSIC_BASH}" != "" ]] -then - return -fi - - - -# Includes -#----------------------------------------------------------------------------------------------------------------------------------- - -. /usr/global/lib/default.bash - - - - - -# Global Variable -#----------------------------------------------------------------------------------------------------------------------------------- - -declare -g MUSIC_BASH=1 - -declare -Ag FLAC_2_MP3_TAB=( - [TRACKNUMBER]=TRCK - [TRACKTOTAL]=TRCK - [TITLE]=TIT2 - [ALBUM]=TALB - [ARTIST]=TPE1 - [COMPOSER]=TCOM - [ARRANGER]=IPLS - [CONDUCTOR]=TPE3 - [REMIXER]=TPE4 - [AUTHOR]=TEXT - [WRITER]=TEXT - [LYRICIST]=TEXT - [ALBUMARTIST]=TPE2 - [DATE]=TDRC - [GENRE]=TCON - [COMPILATION]=TCMP - [DISCTOTAL]=TPOS - [DISCNUMBER]=TPOS - [LABEL]=XXXX - [PUBLISHER]=TPUB - [ISRC]=TSRC - [BARCODE]=TXXX - [CATALOGNUMBER]=TXXX - [COPYRIGHT]=TCOP - [LICENSE]=USER - [COMMENT]=COMM - [DESCRIPTION]=TIT3 - [ENCODER]=TSSE - [MEDIA]=TMED - [LANGUAGE]=TLAN - [LYRICS]=USLT -) - -declare -Ag MP3_2_FLAC_TAB=( - [TRCK]=TRACKNUMBER:TRACKTOTAL - [TIT2]=TITLE - [TALB]=ALBUM - [TPE1]=ARTIST - [TCOM]=COMPOSER - [IPLS]=ARRANGER - [TPE3]=CONDUCTOR - [TPE4]=REMIXER - [TEXT]=AUTHOR:WRITER:LYRICIST - [TPE2]=ALBUMARTIST - [TDRC]=DATE - [TCON]=GENRE - [TCMP]=COMPILATION - [TPOS]=DISCNUMBER:DISCTOTAL - [TPUB]=PUBLISHER - [TSRC]=ISRC - [TXXX]=BARCODE:CATALOGNUMBER - [TCOP]=COPYRIGHT - [USER]=LICENSE - [COMM]=COMMENT - [TIT3]=DESCRIPTION - [TSSE]=ENCODER - [TMED]=MEDIA - [TLAN]=LANGUAGE - [USLT]=LYRICS -) - -declare -g FLAC_TAG_LIST="TRACKNUMBER TRACKTOTAL TITLE ALBUM ARTIST COMPOSER ARRANGER CONDUCTOR REMIXER AUTHOR WRITER LYRICIST ALBUMARTIST DATE GENRE COMPILATION LABEL PUBLISHER ISRC BARCODE UPC COPYRIGHT LICENSE COMMENT DESCRIPTION ENCODER MEDIA LANGUAGE LYRICS" -declare -g FLAC_TAG_COND=$(echo '('${FLAC_TAG_LIST}')' | sed -e 's/ /|/g') - -declare -g NODEF_TAG_LIST="TRACKNUMBER TITLE ISRC LYRICS" -declare -g NODEF_TAG_COND=$(echo '('${NODEF_TAG_LIST}')' | sed -e 's/ /|/g') - - - - - -#----------------------------------------------------------------------------------------------------------------------------------- -# Fix Name -#----------------------------------------------------------------------------------------------------------------------------------- -# Standardise Name -#----------------------------------------------------------------------------------------------------------------------------------- -# $1: Input Name -# $2: SED Substitute Patern -# Out: Output Name -#----------------------------------------------------------------------------------------------------------------------------------- - -function fix_name -{ - input_name="$1" - ssp="$2" - - if [[ "${ssp}" != "" ]] - then - sse="s/${ssp}" - else - sse="s/^//" - fi - - echo ${input_name} | - sed -e 's/[ ,!/?:]/_/g' \ - -e "s/['’´]/_/g" \ - -e 's/\[/-/g' -e 's/\]//g' \ - -e 's/(/-/g' -e 's/)//g' \ - -e 's/__/_/g' -e 's/_\././g' -e 's/_-/-/g' -e 's/--/-/g' -e 's/-_/-/g' \ - -e 's/à/a/g' -e 's/á/a/g' -e 's/ä/a/g' -e 's/â/a/g' -e 's/ã/a/g' -e 's/é/e/g' -e 's/è/e/g' -e 's/ê/e/g' -e 's/ë/e/g' -e 's/ï/i/g' -e 's/î/i/g' -e 's/í/i/g' -e 's/ô/o/g' -e 's/ö/o/g' -e 's/ó/o/g' -e 's/ù/u/g' -e 's/ü/u/g' -e 's/û/u/g' -e 's/ú/u/g' -e 's/ç/c/g' -e 's/ñ/n/g' \ - -e 's/À/a/g' -e 's/Á/a/g' -e 's/Ä/a/g' -e 's/Â/a/g' -e 's/Ã/a/g' -e 's/É/e/g' -e 's/È/e/g' -e 's/Ê/e/g' -e 's/Ë/e/g' -e 's/Ï/i/g' -e 's/Î/i/g' -e 's/Í/i/g' -e 's/Ô/o/g' -e 's/Ö/o/g' -e 's/Ó/o/g' -e 's/Ù/u/g' -e 's/Ü/u/g' -e 's/Û/u/g' -e 's/Ú/u/g' -e 's/Ç/c/g' -e 's/Ñ/n/g' \ - -e 's/¿//g' \ - -e 's/[+&]/and/g' -e 's/"/_inch/g' \ - -e 's/#//g' \ - -e 's/^[_-]*//' \ - -e 's/[_-]*$//' \ - -e "${sse}" | - tr '[:upper:]' '[:lower:]' -} - - - - - -#----------------------------------------------------------------------------------------------------------------------------------- -# Fix File Name -#----------------------------------------------------------------------------------------------------------------------------------- -# Standardise File Name -#----------------------------------------------------------------------------------------------------------------------------------- -# $1: Input File Name -# $2: SED Substitute Patern -# Out: Output File Name -#----------------------------------------------------------------------------------------------------------------------------------- - -function fix_file_name -{ - input_file_name="$1" - ssp="$2" - - fix_name "${input_file_name}" "${ssp}" | - sed -e 's/\(^[0-9]*\)./\1-/' -} - - - - - -# TagTab Alloc -#----------------------------------------------------------------------------------------------------------------------------------- - -function tagtab_alloc -{ - unset tagtab - declare -Ag tagtab - - declare -g taglist - taglist=":" -} - - - - - -# Tag Exist -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_exist -{ - tag="$1" - - echo ${taglist} | grep -e ":${tag}:" -} - - - - - -# TagTab Read -#----------------------------------------------------------------------------------------------------------------------------------- - -function tagtab_read -{ - track_id="$1" - track_file="$2" - mode="$3" - - tmp_file=$(mktemp) - - case "${track_file}" - in - *.flac) - metaflac --export-tags-to=- "${track_file}" | sed -e 's/^[^=]*=/\U&\E/' > ${tmp_file} - - while read line - do - tag="${line/=*}" - - if [[ ${line/*=*/=} == "=" ]] && [[ "${tag}" != "" ]] - then - value="$(tag_read "${track_file}" "${tag}")" - - if [[ "$(tag_exist ${tag})" == "" ]] - then - taglist="${taglist}${tag}:" - fi - - if [[ ( "${mode}" != "FACTORING" ) || ( "${tag}" =~ ^${NODEF_TAG_COND}$ ) || ( "${tagtab["0,${tag}"]}" != "" ) ]] - then - if [[ "${tagtab["0,${tag}"]}" != "${value}" ]] - then - tagtab["${track_id},${tag}"]="$value" - fi - else - tagtab["0,${tag}"]="${value}" - fi - fi - done < ${tmp_file} - ;; - - *.mp3) - mid3v2 --list "${track_file}" | tail -n +2 | sed -e 's/^[^=]*=/\U&\E/' > ${tmp_file} - - while read line - do - mp3tag="${line/=*}" - - value="$(tag_read "${track_file}" "${mp3tag}")" - - if [[ "${line/*=*/=}" == "=" ]] && [[ "${mp3tag}" != "" ]] && [[ "${MP3_2_FLAC_TAB["${mp3tag}"]}" != "" ]] - then - tag="${MP3_2_FLAC_TAB["${mp3tag}"]}" - - if [[ "$(tag_exist ${tag})" == "" ]] - then - taglist="${taglist}${tag}:" - fi - - if [[ ( "${mode}" != "FACTORING" ) || ( "${tag}" =~ ^${NODEF_TAG_COND}$ ) || ( "${tagtab["0,${tag}"]}" != "" ) ]] - then - if [[ "${tagtab["0,${tag}"]}" != "${value}" ]] - then - tagtab["${track_id},${tag}"]="$value" - fi - else - tagtab["0,${tag}"]="${value}" - fi - fi - done < ${tmp_file} - ;; - - *) - err_echo "tagtab_read: Unknown file format: ${track_file}" - ;; - esac - - if [[ ${taglist} == ":" ]] - then - taglist="" - fi - - \rm -f ${tmp_file} -} - - - - - -# TagTab Load -#----------------------------------------------------------------------------------------------------------------------------------- - -function tagtab_load -{ - metadata_file="$1" - mode="$2" - - track_id=0 - eoa="false" - - while read -r line && [[ "${eoa}" != "true" ]] - do - tag="${line/=*}" - value="${line/${tag}=}" - - case "${tag}" - in - @${FLAC_TAG_COND}) - tagtab["${track_id},${tag}"]="$value" - ;; - - DEF) - ;; - - SOT) - track_id=$((${track_id} + 1)) - ;; - - EOT) - ;; - - EOA) - eoa="true" - ;; - - *) - err_echo "tagtab_load: Unkwown tag: '${tag}'" - ;; - esac - done < "${metadata_file}" -} - - - - - -# TagTab Dump -#----------------------------------------------------------------------------------------------------------------------------------- - -function tagtab_dump -{ - track_id="$1" - dump_mode="$2" - - case "${dump_mode}" in - "STANDARD") - dump_list="${FLAC_TAG_LIST}" - ;; - - "PASSTHROUGH") - dump_list="${taglist//:/ }" - ;; - - "CUSTOM") - dump_list="$3" - ;; - - esac - - - - for tag in ${dump_list} - do - if [[ "${tagtab["${track_id},${tag}"]}" != "" ]] - then - echo "${tag}=${tagtab["${track_id},${tag}"]}" - fi - done -} - - - - - -# Tag Get -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_get -{ - declare -n return=$1 - track_id=$2 - tag=$3 - - - return="${tagtab["${track_id},${tag}"]}" - - if [[ "${return}" == "" ]] - then - return="${tagtab["0,${tag}"]}" - - if [[ "${return}" == "" ]] && [[ "${tag}" == "TRACKNUMBER" ]] - then - return="$(printf "%02d" ${track_id})" - fi - fi -} - - - - - -# Tag Save -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_save -{ - target_file=$1 - track_id=$2 - mode=$3 - - - - if [[ "${mode}" == "CLEAN" ]] - then - tag_all_delete "${target_file}" "" - fi - - for tag in ${FLAC_TAG_LIST} - do -# if [[ "${tagtab["${track_id},${tag}"]}" == "" ]] -# then -# value="${tagtab["0,${tag}"]}" -# -# if [[ "${value}" == "" ]] && [[ "${tag}" == "TRACKNUMBER" ]] -# then -# value="$(printf "%02d" ${track_id})" -# fi -# else -# value="${tagtab["${track_id},${tag}"]}" -# fi - - tag_get value "${track_id}" "${tag}" - - tag_delete "${target_file}" "${tag}" - - if [[ "${value}" != "" ]] - then - tag_write "${target_file}" "${tag}" "${value}" - fi - done -} - - - - - -# Tag Read -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_read -{ - track_file="$1" - tag="$2" - - case "${track_file}" - in - *.flac) - metaflac --show-tag="${tag}" "${track_file}" | sed -e 's/^[^=]*=//' -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' - ;; - - *.mp3) -# mid3v2 --list "${track_file}" | tail -n +2 | sed -e 's/^[^=]*=/\U&\E/' | grep -e "^${FLAC_2_MP3_TAB["${tag}"]}" | sed -e 's/^[^=]*=//' -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' - mid3v2 --list "${track_file}" | tail -n +2 | grep -e "^${tag}" | sed -e 's/^[^=]*=//' -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' - ;; - - *) - err_echo "tag_read: Unknown file format: ${track_file}" - ;; - esac -} - - - - - -# Tag Write -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_write -{ - track_file="$1" - tag="$2" - value="$3" - - - - value="$(echo -e "$(escape_str "${value}")")" - - case "${track_file}" - in - *.flac) - cmd="metaflac --set-tag=\"${tag}=${value}\" \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - *.mp3) - cmd="mid3v2 --\"${FLAC_2_MP3_TAB["${tag}"]}\" \"${value}\" \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - *) - err_echo "tag_write: Unknown file format: ${track_file}" - ;; - esac -} - - - - - -# Tag Delete -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_delete -{ - track_file="$1" - tag="$2" - - case "${track_file}" - in - *.flac) - cmd="metaflac --remove-tag=\"${tag}\" \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - *.mp3) - cmd="mid3v2 --delete-frames=\"${FLAC_2_MP3_TAB["${tag}"]}\" \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - *) - err_echo "tag_delete: Unknown file format: ${track_file}" - ;; - esac -} - - - - - -# Tag All Delete -#----------------------------------------------------------------------------------------------------------------------------------- - -function tag_all_delete -{ - track_file="$1" - header_type="$2" - - if [[ "${header_type}" == "" ]] - then - case "${track_file##*.}" - in - flac) - header_type="ogg" - ;; - - mp3) - header_type="id3" - ;; - esac - fi - - if [[ ( "${header_type}" == "ogg") && ( "${track_file##*.}" == "mp3") ]] - then - err_echo "tag_all_delete: Can't remove ogg tags from mp3 file!" - else - case "${header_type}" - in - ogg) - cmd="metaflac --remove-all-tags \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - id3) - cmd="mid3v2 --delete-all \"${track_file}\"" - exec_cmd "${cmd}" - ;; - - *) - err_echo "tag_all_delete: Unknown header type: ${header_type}" - ;; - esac - fi - -} - - - - - -# Album Type Get -#----------------------------------------------------------------------------------------------------------------------------------- - -function album_type_get -{ - track_file="$1" - - for type in various_artists tribute original_soundtrack child - do - if [[ ${track_file} == */${type}/* ]] - then - echo "${type}" - fi - done -}