get-tracks/get-tracks.sh

210 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env sh
get_time(){
echo "$*" | sed "s/[ \t].*//"
}
get_title(){
echo "$*" | cut -d ' ' -f 2-
}
reverse_word_order(){
local result=
for word in $@; do
result="$word $result"
done
echo "$result"
}
# bc is mandatory: arythmetic operations are very limited in ash.
get_seconds(){
number_position=0
value=0
values=$(echo "$*" | sed 's/:/\
/g' | sed "s/^0//")
for i in $(reverse_word_order $values); do
case $number_position in
0) value=$(echo "$value + $i " | bc);;
1) value=$(echo "$value + (60 * $i)" | bc);;
2) value=$(echo "$value + (3600 * $i)" | bc);;
*) echo "invalid timecode $*"; exit 1;;
esac
number_position=$((number_position+1))
done
echo $value
}
# Get a more usable time representation for the beginning and the end of songs.
get_values(){
audio_file="$1"
time_file="$2"
track_number=1
while read X; do
if [ $track_number -ne 1 ]; then
to_unformatted=$(get_time $X)
to_s=$(get_seconds $to_unformatted)
echo "$from_s $to_s $title"
fi
from_unformatted=$(get_time $X)
from_s=$(get_seconds $from_unformatted)
title=$(get_title $X)
if [ "$NONUMBER" = "" ]; then
track_n=$track_number
if [ $track_number -lt 10 ]; then
track_n="0$track_number"
fi
title="${track_n}${SEPARATOR}${title}"
fi
track_number=$(echo $track_number + 1 | bc)
done < "${time_file}"
echo "$from_s $eof_marker $title"
}
run_ffmpeg(){
file=$1
from=$2
duration=$3
final_title=$4
LOG_LEVEL="-loglevel error"
FROM="-ss $from"
if [ "$duration" = "" ]; then
DURATION=""
else
DURATION="-t $duration"
fi
INPUT_FILE="-i $file"
OUTPUT_FILE="$final_title"
case "v$VERBOSITY" in
v0)
;;
v1)
echo "extracting '$final_title'"
;;
v2)
echo "ffmpeg $LOG_LEVEL $FROM $DURATION $INPUT_FILE '$OUTPUT_FILE'"
;;
*)
echo "verbosity is not set properly" >&2
exit 1
;;
esac
if [ "$SIMULATION" = "" ]; then
$(< /dev/null ffmpeg $LOG_LEVEL $FROM $DURATION $INPUT_FILE "$OUTPUT_FILE")
fi
}
rip(){
track_start_s=0
track_end_s=0
audio_file="$1"
time_file="$2"
get_values "$audio_file" "$time_file" | while read LINE; do
track_start_s=$(echo $LINE | cut -d ' ' -f 1)
track_end_s=$(echo $LINE | cut -d ' ' -f 2)
track_title=$(echo $LINE | cut -d ' ' -f 3-)
if [ "$track_end_s" != "$eof_marker" ]; then
track_duration=$(echo "$track_end_s - $track_start_s" | bc)
else
track_duration=""
fi
run_ffmpeg "${audio_file}" "${track_start_s}" "${track_duration}" "${track_title}.${FORMAT}"
done
}
usage(){
echo "usage: $0 command"
echo "command: show <single-file-playlist> <song-list>"
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 non empty, 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)"
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"
}
if [ $# -lt 1 ]; then
usage
exit 0
fi
command=$1
shift
if [ "$FORMAT" = "" ]; then
echo "default FORMAT: opus"
FORMAT="opus"
fi
if [ "$VERBOSITY" = "" ]; then
echo "default VERBOSITY: 1"
VERBOSITY=1
fi
# Assume that there should be a separator.
if [ "$SEPARATOR" = "" ]; then
echo "default SEPARATOR: ' - '"
SEPARATOR=" - "
fi
if [ "$SIMULATION" != "" ]; then
echo "SIMULATION envvar is set: this is a simulation."
fi
# soxi provides the total length of the music file.
#which soxi 2>/dev/null
#total_length=$(soxi -D "${audio_file}" | sed "s/\..*//") # integer values only
eof_marker="END_OF_FILE"
case "x-${command}" in
x-show)
# Takes the audio file in first parameter
if [ $# -ne 2 ]; then
echo "Usage: $0 show music-file time-stamps-file" >&2
exit 1
fi
get_values "$1" "$2"
;;
x-rip)
# Takes the audio file in first parameter
if [ $# -ne 2 ]; then
echo "Usage: $0 show music-file time-stamps-file" >&2
exit 1
fi
rip "$1" "$2"
;;
*)
usage 1>&2
exit 1
esac