a lot of changes, some breaking. see extended comment

- no more "releases". they don't work well for a shell script of this small scope
- updates are checked against latest commit, and can be applied automatically
  if  the user doesn't have git installed
- for real now, the script will not automatically convert and rather show usage
  if a directory isn't entered. I accidentally ran the script once and had
  like 30 opus files spew out and had not a fun time cleaning it up
- for some reason, while I made a comment about not supporting filenames
  with newlines, I never had a user-friendly notification or check for this.
  now I do! so it'll notify you if the filepath has a newline in it
- keepkeys and removekeys can be comma separated instead of pipe separated now.
  a bit friendlier to type now. you can still use pipes and it works fine!
This commit is contained in:
yosh 2024-02-01 23:10:41 -05:00
parent 626630a4c1
commit 513267edab
2 changed files with 59 additions and 38 deletions

View File

@ -1,50 +1,50 @@
# 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
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
DIRECTORY can be specified multiple times
${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}
(blame id3. just use opus)
-h show script help
-u check for updates
-v verbose output (messy with multithreading)
-V very verbose output (VERY messy, use only for debugging and with like, -j 1)
-v verbose output ${YELLOW}(messy with multithreading)${RESET}
-V very verbose output ${RED}(VERY messy, use only for debugging and with like, -j 1)${RESET}
-i ignore script-stopping warnings
-d delete original flac files after transcoding
-3 switch output filetype to mp3
-b <BITRATE> output bitrate in kbits (default 128)
this value is variable for opus & CBR for mp3
-l <LEVEL> mp3 only: use specified mp3 variable quality (0-9). integer only
OVERRIDES -b
${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 PIPE-separated list of keys to keep, case-insensitive
(i.e. -k 'artist|title|albumartist|album|date')
if both -k and -r are not present, all keys are kept.
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
if set to "ALL" (with capitalization), all keys are removed
${YELLOW}if set to "ALL" (with capitalization), all keys are removed${RESET}
-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

View File

@ -1,6 +1,5 @@
#!/bin/sh
VERSION=1.4.6
RED="$(printf '\033[38;5;9m')"
GREEN="$(printf '\033[38;5;10m')"
YELLOW="$(printf '\033[38;5;11m')"
@ -16,7 +15,7 @@ if [ -n "${NO_COLOR:-}" ]; then
fi
errecho() {
>&2 echo "$*$RESET"
>&2 printf '%s\n' "$*$RESET"
}
fail() {
@ -28,15 +27,33 @@ 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
}
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..."
tmpupdate=$(mktemp)
curl -s -o "$tmpupdate" 'https://git.unix.dog/yosh/flacconv/raw/branch/main/flacconv' || fail "curl request failed! retry probably"
if cmp "$tmpupdate" "$0"; then
errecho "you are updated!"
else
printf '%s' "the latest commit differs from the current version. if you use git, please git pull the repo for the update"
printf '%s' "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]) chmod +x "$tmpupdate" && mv -f "$tmpupdate" "$0" && errecho "updated!" || fail "applying update failed! retry probably" ;;
*) errecho "not applying update!" ;;
esac
fi
exit 0
}
@ -155,11 +172,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}
@ -177,9 +193,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
@ -219,8 +235,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
@ -237,8 +253,8 @@ else
fi
[ -n "$RMENCTAG" ] && { command -v opustags 1>/dev/null 2>&1 || fail 'opustags is not installed! this is required for -e (opustags)' ; }
# if no arg provided, use cwd
[ "$#" -eq 0 ] && set -- .
# 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
FLACFILES="$(find "$@" -type f -name "*.[fF][lL][aA][cC]")"
@ -271,7 +287,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