get-tracks/get-tracks.sh

276 lines
5.0 KiB
Bash
Raw Normal View History

2021-03-27 21:18:08 +01:00
#!/usr/bin/env sh
2021-04-06 16:09:15 +02:00
# From a single byte in hexadecimal per line
# to lines ending with 0a (hex for '\n').
regroup_lines(){
awk '
BEGIN {
2021-04-06 16:09:15 +02:00
line_start=1
}
{
2021-04-06 16:09:15 +02:00
if (line_start == 1)
line = $1;
else
line = line " " $1;
2021-04-06 16:09:15 +02:00
line_start = 0;
if ($1 == "0a") {
print line;
2021-04-06 16:09:15 +02:00
line_start = 1
}
}
END {
2021-04-06 16:09:15 +02:00
if (line_start == 0)
print line
}
'
2021-03-27 21:18:08 +01:00
}
2021-04-06 16:09:15 +02:00
# From to '
simple_quote(){
sed "s/e2 80 99/27/g"
2021-03-27 21:18:08 +01:00
}
remove_multibyte_characters(){
sed "s/e2 80 .. //g"
2021-03-27 21:18:08 +01:00
}
2021-04-06 16:09:15 +02:00
# Convert input into hexadecimal and a single byte per line.
to_hex_one_column(){
xxd -p -c 1
2021-03-27 21:18:08 +01:00
}
2021-04-06 16:09:15 +02:00
# Reverse hexadecimal to original value.
from_hex(){
xxd -p -r
}
2021-03-27 21:18:08 +01:00
2021-04-06 16:09:15 +02:00
# Remove non ascii characters, convert "" to "'".
to_ascii(){
2021-04-06 16:09:15 +02:00
to_hex_one_column | # Convert input into hexadecimal and a single byte per line.
regroup_lines | # Required to easily match multi-byte characters.
simple_quote | # Convert "" to "'".
remove_multibyte_characters | # Remove non ascii values.
from_hex # Convert back from hex.
}
2021-03-27 21:18:08 +01:00
2021-04-06 17:24:26 +02:00
process_end_of_songs(){
awk -v NONUMBER="$NONUMBER" -v SEPARATOR="$SEPARATOR" '
BEGIN {
OFS=" "
}
{
if (NR > 1) {
print timestamp, $1, title;
}
timestamp = $1;
if (NONUMBER == 1) {
title = $2
}
else {
if (NR < 10) {
title = "0" NR SEPARATOR $2
}
else {
title = NR SEPARATOR $2
}
}
for (i=3; i <= NF; i++) {
title = title " " $i
}
}
END {
print timestamp, "END_OF_FILE", title;
}
'
}
2021-03-27 21:18:08 +01:00
first_column_to_seconds(){
awk '
{
# from 10:30 to 630
n = split ($1, arr, ":")
for (i = 0; i <= n; i++) {
if (i == 0) {
v = arr[n-i];
}
else if (i == 1) {
v += 60 * arr[n-i];
}
else if (i == 2) {
v += 3600 * arr[n-i];
}
}
$1 = v;
print;
v = 0;
}
'
}
2021-03-27 21:18:08 +01:00
# Get a more usable time representation for the beginning and the end of songs.
process_time_file(){
2021-04-06 17:24:26 +02:00
to_ascii | first_column_to_seconds | process_end_of_songs
2021-03-27 21:18:08 +01:00
}
run_ffmpeg(){
file=$1
from=$2
2021-04-06 17:24:26 +02:00
to=$3
final_title=$4
LOG_LEVEL="-loglevel error"
FROM="-ss $from"
2021-04-06 17:24:26 +02:00
TO=""
if [ "$to" != "" ]; then
TO="-to $to"
2021-04-05 02:33:10 +02:00
fi
INPUT_FILE="-i $file"
OUTPUT_FILE="$final_title"
case "v$VERBOSITY" in
v0)
;;
v1)
echo "extracting '$final_title'"
;;
v2)
2021-04-06 17:24:26 +02:00
echo "ffmpeg $LOG_LEVEL $FROM $TO $INPUT_FILE '$OUTPUT_FILE'"
;;
*)
echo "verbosity is not set properly" >&2
exit 1
;;
esac
if [ "$SIMULATION" = "" ]; then
2021-04-06 17:24:26 +02:00
$(< /dev/null ffmpeg $LOG_LEVEL $FROM $TO $INPUT_FILE "$OUTPUT_FILE")
2021-03-27 21:18:08 +01:00
fi
}
rip(){
audio_file="$1"
time_file="$2"
2021-04-06 16:09:15 +02:00
process_time_file < "$time_file" | while read LINE; do
2021-04-06 17:24:26 +02:00
track_start=$(echo $LINE | cut -d ' ' -f 1)
track_end=$(echo $LINE | cut -d ' ' -f 2)
track_title=$(echo $LINE | cut -d ' ' -f 3-)
2021-04-06 17:24:26 +02:00
if [ "$track_end" = "END_OF_FILE" ]; then
track_end=""
2021-04-05 02:33:10 +02:00
fi
2021-03-27 21:18:08 +01:00
2021-04-06 17:24:26 +02:00
run_ffmpeg "${audio_file}" "${track_start}" "${track_end}" "${track_title}.${FORMAT}"
2021-03-27 21:18:08 +01:00
done
}
usage(){
echo "usage: $0 command"
2021-04-06 16:09:15 +02:00
echo "command: show <song-list>"
2021-03-27 21:18:08 +01:00
echo "command: rip <single-file-playlist> <song-list>"
echo
echo "song-list line format example: 1:30 My second track of the playlist"
echo "show output format: start end title"
echo
echo "envvar: SIMULATION, if non empty, do not invoke ffmpeg"
echo "envvar: NONUMBER, if equals 1, do not write song number"
echo "envvar: FORMAT [mp3,ogg,opus,…], see the ffmpeg documentation"
echo "envvar: SEPARATOR [separator] (default: ' - '), write song number, with this separator"
echo " example with SEPARATOR='_': song names will be 01_song.opus 02_song.opus…"
echo "envvar: VERBOSITY [0-3] (default: 1)"
2021-04-06 17:24:26 +02:00
echo " verbosity 0: no output exept errors from ffmpeg"
echo " verbosity 1: simple indications on the current track being extracted"
echo " verbosity 2: print actual ffmpeg commands the script currently runs"
2021-03-27 21:18:08 +01:00
}
if [ $# -lt 1 ]; then
usage
exit 0
fi
command=$1
shift
if [ "$FORMAT" = "" ]; then
echo "default FORMAT: opus"
FORMAT="opus"
else
echo "FORMAT: $FORMAT"
fi
if [ "$VERBOSITY" = "" ]; then
echo "default VERBOSITY: 1"
VERBOSITY=1
else
echo "VERBOSITY level: $VERBOSITY"
fi
if [ "$NONUMBER" = "" ]; then
echo "default NONUMBER: disabled"
NONUMBER=0
# Assume that there should be a separator.
if [ "$SEPARATOR" = "" ]; then
echo "default SEPARATOR: ' - '"
SEPARATOR=" - "
else
echo "SEPARATOR: '$SEPARATOR'"
fi
else
echo "NONUMBER: won't prefix tracks"
SEPARATOR=""
fi
if [ "$SIMULATION" != "" ]; then
echo "SIMULATION envvar is set: this is a simulation."
fi
</dev/null xxd -p >/dev/null 2>/dev/null
if [ $? -ne 0 ]; then
echo "xxd: you don't have an xxd program with '-p' option." 1>&2
exit 1
fi
</dev/null xxd -r >/dev/null 2>/dev/null
if [ $? -ne 0 ]; then
echo "xxd: you don't have an xxd program with '-r' option." 1>&2
exit 1
fi
2021-04-05 02:33:10 +02:00
2021-03-27 21:18:08 +01:00
case "x-${command}" in
x-show)
# Takes the audio file in first parameter
2021-04-06 16:09:15 +02:00
if [ $# -ne 1 ]; then
echo "Usage: $0 show time-stamps-file" >&2
2021-03-27 21:18:08 +01:00
exit 1
fi
2021-04-06 16:09:15 +02:00
process_time_file < "$1"
2021-03-27 21:18:08 +01:00
;;
x-rip)
# Takes the audio file in first parameter
if [ $# -ne 2 ]; then
echo "Usage: $0 show music-file time-stamps-file" >&2
2021-03-27 21:18:08 +01:00
exit 1
fi
rip "$1" "$2"
;;
2021-03-27 21:18:08 +01:00
*)
usage 1>&2
exit 1
esac