Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
yosh | 1253d60e45 | |
yosh | 9fbbc2fbb6 | |
yosh | 66ffa456eb | |
yosh | 201a3916cd | |
yosh | 513267edab | |
yosh | 626630a4c1 | |
yosh | e663630d39 | |
yosh | 03cb6b431b |
28
README.md
28
README.md
|
@ -1,25 +1,25 @@
|
|||
# flacconv
|
||||
flacconv is a (hopefully) 100% POSIX and portable[^1] shell script that recursively converts directories of flac files to opus/mp3.
|
||||
flacconv is a 100% POSIX and (hopefully) portable[^1] shell script that recursively converts directories of flac files to opus/mp3.
|
||||
|
||||
when invoked with no arguments, it recursively converts the current directory's flac files to opus with a bitrate of 128k, retaining all metadata and not deleting the original flac files
|
||||
with no flags, it recursively converts flac files in the specified directory (or directories) to opus with a bitrate of 128k, retaining all metadata and not deleting the original flac files
|
||||
|
||||
it also has options for you to change the bitrate, use a variable quality for mp3, keep/remove metadata, and parallel processing
|
||||
|
||||
## dependencies
|
||||
- Some implementation of a shell and [POSIX Utilities](https://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html) (usually, this is GNU coreutils, which you probably have)
|
||||
- `mktemp -u` (again, probably have this already)
|
||||
- `flac`
|
||||
- `flac` and `metaflac` (usually bundled together)
|
||||
- `lame` (only if encoding to mp3)
|
||||
- `opus-tools` (only if encoding to opus)
|
||||
- [opustags](https://github.com/fmang/opustags) (optional, to use the -e option)
|
||||
- [`opustags`](https://github.com/fmang/opustags) (optional, to use the -e option)
|
||||
- `curl` (optional, for checking for updates)
|
||||
|
||||
## usage
|
||||
```
|
||||
usage: flacconv [-huvVipe3] [-b BITRATE] [-l LEVEL] [-k KEYS] [-r KEYS] [-j THREADS] [--] [DIRECTORY...]
|
||||
usage: flacconv [-huvVipe3] [-b BITRATE] [-l LEVEL] [-k KEYS] [-r KEYS] [-j THREADS] [--] <DIRECTORY...>
|
||||
|
||||
flacconv recursively converts directories of flac files to opus/mp3
|
||||
DIRECTORY can be specified multiple times. if omitted, the current directory is used
|
||||
by default, this script outputs opus with variable bitrate 128k
|
||||
DIRECTORY can be specified multiple times
|
||||
IF ENCODING TO MP3, -k AND -r WILL NOT WORK. the only metadata that will be kept is the following:
|
||||
TITLE, ARTIST, ALBUM, ALBUMARTIST, DATE, GENRE, TRACKNUMBER, COMMENT, and the cover picture
|
||||
(blame id3. just use opus)
|
||||
|
@ -36,15 +36,15 @@ IF ENCODING TO MP3, -k AND -r WILL NOT WORK. the only metadata that will be kept
|
|||
-l <LEVEL> mp3 only: use specified mp3 variable quality (0-9). integer only
|
||||
OVERRIDES -b
|
||||
-k <KEYS> keep specified flac metadata KEYS in output file
|
||||
keys can be checked with metaflac --export-tags-to=- FILE
|
||||
option argument is a PIPE-separated list of keys to keep, case-insensitive
|
||||
(i.e. -k 'artist|title|albumartist|album|date')
|
||||
keys can be seen using metaflac --export-tags-to=- file.flac
|
||||
argument is a comma or pipe-separated list of keys, case-insensitive
|
||||
(i.e. -k "artist,title,albumartist,album,date")
|
||||
if both -k and -r are not present, all keys are kept.
|
||||
-r <KEYS> remove specified flac metadata KEYS in output file
|
||||
option argument is of the same format as -k
|
||||
if set to "ALL" (with capitalization), all keys are removed
|
||||
-p remove embedded picture in output files
|
||||
-e remove the "encoder" tags that automatically gets applied with opusenc
|
||||
-e remove the "encoder" tag that automatically gets applied with opusenc
|
||||
(requires opustags)
|
||||
-j <THREADS> use the specified amount of threads for parallel processing
|
||||
if omitted, CPU core count will be used
|
||||
|
@ -57,14 +57,14 @@ recursively convert a directory of flacs to opus 128k, removing the picture and
|
|||
|
||||
recursively convert the current directory to mp3 320k
|
||||
|
||||
`flacconv -b 320 -3`
|
||||
`flacconv -b 320 -3 .`
|
||||
|
||||
recursively convert current directory to opus 160k, while removing any COMMENT or DESCRIPTION tags
|
||||
|
||||
`flacconv -b 160 -r "COMMENT|DESCRIPTION"`
|
||||
`flacconv -b 160 -r comment,description .`
|
||||
|
||||
recursively convert current directory to mp3 v0, removing all pictures
|
||||
|
||||
`flacconv -3 -l 0 -p`
|
||||
`flacconv -3 -l 0 -p .`
|
||||
|
||||
[^1]: tested with dash, bash, and yash (set -o posixly-correct) on linux. further testing encouraged
|
||||
|
|
87
flacconv
87
flacconv
|
@ -1,6 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
VERSION=1.4.5
|
||||
RED="$(printf '\033[38;5;9m')"
|
||||
GREEN="$(printf '\033[38;5;10m')"
|
||||
YELLOW="$(printf '\033[38;5;11m')"
|
||||
|
@ -9,14 +8,12 @@ set -euf
|
|||
BN="${0##*/}"
|
||||
NL='
|
||||
'
|
||||
export POSIXLY_CORRECT=1
|
||||
|
||||
if [ -n "${NO_COLOR:-}" ]; then
|
||||
RED="" GREEN="" YELLOW="" RESET=""
|
||||
fi
|
||||
|
||||
errecho() {
|
||||
>&2 echo "$*$RESET"
|
||||
>&2 printf '%s\n' "$*$RESET"
|
||||
}
|
||||
|
||||
fail() {
|
||||
|
@ -28,27 +25,43 @@ warn() {
|
|||
errecho "${YELLOW}warning: $BN: $*"
|
||||
if [ -z "$IGNOREWARNINGS" ]; then
|
||||
errecho 'you can ignore stopping for warnings in the future with -i'
|
||||
errecho 'press enter to continue, or C-c to quit'
|
||||
errecho 'press enter to continue, or Ctrl-c to quit'
|
||||
read -r __
|
||||
fi
|
||||
}
|
||||
|
||||
_tempdir() {
|
||||
set +u
|
||||
[ -n "$TMPDIR" ] || \
|
||||
{ [ -n "$TEMP" ] && TMPDIR="$TEMP"; } || \
|
||||
{ [ -n "$TMP" ] && TMPDIR="$TMP"; } || \
|
||||
{ [ -d "/tmp" ] && TMPDIR="/tmp"; } || \
|
||||
{ [ -d "/var/tmp" ] && TMPDIR="/var/tmp"; } || \
|
||||
{ [ -d "/usr/tmp" ] && TMPDIR="/usr/tmp"; } || \
|
||||
TMPDIR="$PWD"
|
||||
set -u
|
||||
cleanup() {
|
||||
[ -f "${tmpupdate:-}" ] && rm "$tmpupdate"
|
||||
:
|
||||
}
|
||||
trap "cleanup" INT HUP QUIT TERM EXIT
|
||||
|
||||
checkupdate() {
|
||||
errecho "you are running version ${GREEN}${VERSION}"
|
||||
errecho "until I learn if forgejo has an equivalent for github's latest release download shenanigans just check to see if this version matches the latest release"
|
||||
errecho "https://git.unix.dog/yosh/flacconv/releases/latest"
|
||||
errecho "checking for updates from https://git.unix.dog/yosh/flacconv/src/branch/main/flacconv..."
|
||||
errecho
|
||||
tmpupdate=$(mktemp)
|
||||
curl -s -o "$tmpupdate" 'https://git.unix.dog/yosh/flacconv/raw/branch/main/flacconv' || fail "curl request failed! retry probably"
|
||||
if cmp -s "$tmpupdate" "$0"; then
|
||||
errecho "you are updated!"
|
||||
else
|
||||
errecho "the latest commit differs from the current version. if you use git, please git pull the repo for the update"
|
||||
errecho "you can see the changes here: https://git.unix.dog/yosh/flacconv/commits/branch/main"
|
||||
printf '%s' "if you don't use git, apply update directly? [y/n] " >&2
|
||||
read -r choice
|
||||
case "$choice" in
|
||||
[Yy])
|
||||
if [ -L "$0" ]; then
|
||||
errecho "${RED}your flacconv patch is a symbolic link."
|
||||
errecho "while it is possible to resolve them in a POSIX manner, it's a weird amount of code"
|
||||
errecho "so I humbly ask that you update it manually"
|
||||
exit 1
|
||||
fi
|
||||
mv -f "$tmpupdate" "$0"
|
||||
errecho "updated!"
|
||||
;;
|
||||
*) errecho "not applying update!" ;;
|
||||
esac
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
@ -115,7 +128,7 @@ process_file() {
|
|||
|
||||
# export pic if we're keeping it
|
||||
if [ -z "$RMPIC" ]; then
|
||||
pic="$TMPDIR/${bname%.*}_IMG"
|
||||
pic="$(mktemp "${bname%.*}XXXX")"
|
||||
metaflac --export-picture-to="$pic" "$infile"
|
||||
fi
|
||||
|
||||
|
@ -167,11 +180,10 @@ process_file() {
|
|||
|
||||
usage() {
|
||||
cat >&2 <<-EOF
|
||||
flacconv $VERSION
|
||||
usage: $BN [-huvVipe3] [-b BITRATE] [-l LEVEL] [-k KEYS] [-r KEYS] [-j THREADS] [--] [DIRECTORY...]
|
||||
usage: $BN [-huvVipe3] [-b BITRATE] [-l LEVEL] [-k KEYS] [-r KEYS] [-j THREADS] [--] <DIRECTORY...>
|
||||
|
||||
$BN recursively converts directories of flac files to opus/mp3
|
||||
DIRECTORY can be specified multiple times. if omitted, the current directory is used
|
||||
DIRECTORY can be specified multiple times
|
||||
by default, this script outputs opus with variable bitrate 128k
|
||||
${RED}IF ENCODING TO MP3, -k AND -r WILL NOT WORK.${RESET} the only metadata that will be kept is the following:
|
||||
${YELLOW}TITLE, ARTIST, ALBUM, ALBUMARTIST, DATE, GENRE, TRACKNUMBER, COMMENT, and the cover picture${RESET}
|
||||
|
@ -189,9 +201,9 @@ usage() {
|
|||
-l <LEVEL> mp3 only: use specified mp3 variable quality (0-9). integer only
|
||||
${YELLOW}OVERRIDES -b${RESET}
|
||||
-k <KEYS> keep specified flac metadata KEYS in output file
|
||||
keys can be checked with metaflac --export-tags-to=- FILE
|
||||
option argument is a ${YELLOW}PIPE-separated${RESET} list of keys to keep, case-insensitive
|
||||
(i.e. -k "artist|title|albumartist|album|date")
|
||||
keys can be seen using metaflac --export-tags-to=- file.flac
|
||||
argument is a ${YELLOW}comma or pipe-separated${RESET} list of keys, case-insensitive
|
||||
(i.e. -k "artist,title,albumartist,album,date")
|
||||
${YELLOW}if both -k and -r are not present, all keys are kept.${RESET}
|
||||
-r <KEYS> remove specified flac metadata KEYS in output file
|
||||
option argument is of the same format as -k
|
||||
|
@ -217,7 +229,6 @@ TYPE=opus
|
|||
BITRATE=128
|
||||
THREADS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null)" # hopefully portable enough to not be an issue
|
||||
[ $? -ne 0 ] && warn 'unable to find number of cores! defaulting to 1 thread unless otherwise specified...' && THREADS=1
|
||||
_tempdir # set temp dir
|
||||
|
||||
while getopts :huvVid3peb:l:k:r:j: OPT; do
|
||||
case "$OPT" in
|
||||
|
@ -232,8 +243,8 @@ while getopts :huvVid3peb:l:k:r:j: OPT; do
|
|||
e) RMENCTAG=1 ;;
|
||||
b) BITRATE="$OPTARG" ;;
|
||||
l) VLVL="$OPTARG" ;;
|
||||
k) KEEPKEYS="$OPTARG" ;;
|
||||
r) REMOVEKEYS="$OPTARG" ;;
|
||||
k) KEEPKEYS="$(printf '%s' "$OPTARG" | tr ',' '|')" ;;
|
||||
r) REMOVEKEYS="$(printf '%s' "$OPTARG" | tr ',' '|')" ;;
|
||||
j) THREADS="$OPTARG" ;;
|
||||
*) fail "unknown option: -$OPTARG. run $BN -h to see all options" ;;
|
||||
esac
|
||||
|
@ -241,22 +252,25 @@ done
|
|||
shift "$((OPTIND - 1))"
|
||||
|
||||
[ -n "$REALLYVERBOSE" ] && set -x
|
||||
|
||||
command -v metaflac 1>/dev/null 2>&1 || fail 'flac tools are not installed! (metaflac)'
|
||||
if [ "$TYPE" = "opus" ]; then command -v opusenc 1>/dev/null 2>&1 || fail 'opus-tools is not installed! (opusenc)'
|
||||
else command -v lame 1>/dev/null 2>&1 || fail 'lame is not installed! (lame)'
|
||||
if [ "$TYPE" = "opus" ]; then
|
||||
command -v opusenc 1>/dev/null 2>&1 || fail 'opus-tools is not installed! (opusenc)'
|
||||
else
|
||||
command -v lame 1>/dev/null 2>&1 || fail 'lame is not installed! (lame)'
|
||||
fi
|
||||
[ -n "$RMENCTAG" ] && { command -v opustags 1>/dev/null 2>&1 || fail 'opustags is not installed! this is required for -e (opustags)' ; }
|
||||
|
||||
# if no directory provided, show usage
|
||||
[ "$#" -eq 0 ] && usage && errecho "${NL}to convert the current working directory, use \"flacconv .\"" && exit 1
|
||||
# this script assumes you aren't using newlines in path names
|
||||
# I do not want to change it to account for this
|
||||
# you should never put newlines in paths
|
||||
# it is a very bad idea for many programs
|
||||
FLACFILES="$(find "$@" -type f -name "*.[fF][lL][aA][cC]")"
|
||||
[ -z "$FLACFILES" ] && fail 'no flac files found!'
|
||||
|
||||
# make a fifo/fd for parallel stuff
|
||||
mk_parallel_fd() {
|
||||
fifo_para="$(mktemp -u "$TMPDIR/flacconvXXXX")"
|
||||
fifo_para="$(mktemp -u -t "flacconv.XXXX")"
|
||||
mkfifo "$fifo_para"
|
||||
exec 9<>"$fifo_para"
|
||||
rm -f "$fifo_para"
|
||||
|
@ -281,7 +295,12 @@ run_in_parallel() {
|
|||
errecho "${YELLOW}using ${RESET}$THREADS${YELLOW} threads"
|
||||
mk_parallel_fd
|
||||
while read -r file; do
|
||||
run_in_parallel process_file "$file"
|
||||
if ! [ -f "$file" ]; then
|
||||
errecho "${YELLOW}skipping the file ${RESET}"$file"${YELLOW} because it doesn't exist."
|
||||
errecho "${YELLOW}this most likely means you have a newline in the pathname. fix that!"
|
||||
continue
|
||||
fi
|
||||
run_in_parallel process_file "$file"
|
||||
done <<-EOF
|
||||
$FLACFILES
|
||||
EOF
|
||||
|
|
Loading…
Reference in New Issue