2021-03-27 21:18:08 +01:00
|
|
|
#!/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(){
|
2021-04-05 01:41:16 +02:00
|
|
|
number_position=0
|
|
|
|
value=0
|
2021-03-27 21:18:08 +01:00
|
|
|
|
|
|
|
values=$(echo "$*" | sed 's/:/\
|
|
|
|
/g' | sed "s/^0//")
|
|
|
|
for i in $(reverse_word_order $values); do
|
2021-04-05 01:41:16 +02:00
|
|
|
case $number_position in
|
|
|
|
0) value=$(echo "$value + $i " | bc);;
|
|
|
|
1) value=$(echo "$value + (60 * $i)" | bc);;
|
|
|
|
2) value=$(echo "$value + (3600 * $i)" | bc);;
|
2021-03-27 21:18:08 +01:00
|
|
|
*) echo "invalid timecode $*"; exit 1;;
|
|
|
|
esac
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
number_position=$((number_position+1))
|
2021-03-27 21:18:08 +01:00
|
|
|
done
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
echo $value
|
2021-03-27 21:18:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Get a more usable time representation for the beginning and the end of songs.
|
|
|
|
get_values(){
|
|
|
|
|
|
|
|
audio_file="$1"
|
|
|
|
time_file="$2"
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
track_number=1
|
2021-03-27 21:18:08 +01:00
|
|
|
|
|
|
|
while read X; do
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
if [ $track_number -ne 1 ]; then
|
|
|
|
to_unformatted=$(get_time $X)
|
|
|
|
to_s=$(get_seconds $to_unformatted)
|
|
|
|
echo "$from_s $to_s $title"
|
2021-03-27 21:18:08 +01:00
|
|
|
fi
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
from_unformatted=$(get_time $X)
|
|
|
|
from_s=$(get_seconds $from_unformatted)
|
2021-03-27 21:18:08 +01:00
|
|
|
title=$(get_title $X)
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
if [ "$NONUMBER" = "" ]; then
|
|
|
|
track_n=$track_number
|
|
|
|
if [ $track_number -lt 10 ]; then
|
|
|
|
track_n="0$track_number"
|
|
|
|
fi
|
|
|
|
title="${track_n}${SEPARATOR}${title}"
|
2021-03-27 21:18:08 +01:00
|
|
|
fi
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
track_number=$(echo $track_number + 1 | bc)
|
2021-03-27 21:18:08 +01:00
|
|
|
done < "${time_file}"
|
|
|
|
|
2021-04-05 02:33:10 +02:00
|
|
|
echo "$from_s $eof_marker $title"
|
2021-03-27 21:18:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
run_ffmpeg(){
|
2021-04-05 01:41:16 +02:00
|
|
|
file=$1
|
|
|
|
from=$2
|
|
|
|
duration=$3
|
|
|
|
final_title=$4
|
|
|
|
|
|
|
|
LOG_LEVEL="-loglevel error"
|
|
|
|
FROM="-ss $from"
|
2021-04-05 02:33:10 +02:00
|
|
|
if [ "$duration" = "" ]; then
|
|
|
|
DURATION=""
|
|
|
|
else
|
|
|
|
DURATION="-t $duration"
|
|
|
|
fi
|
2021-04-05 01:41:16 +02:00
|
|
|
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")
|
2021-03-27 21:18:08 +01:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
rip(){
|
2021-04-05 01:41:16 +02:00
|
|
|
track_start_s=0
|
|
|
|
track_end_s=0
|
2021-03-27 21:18:08 +01:00
|
|
|
|
|
|
|
audio_file="$1"
|
|
|
|
time_file="$2"
|
|
|
|
|
|
|
|
get_values "$audio_file" "$time_file" | while read LINE; do
|
2021-04-05 01:41:16 +02:00
|
|
|
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-)
|
2021-04-05 02:33:10 +02:00
|
|
|
if [ "$track_end_s" != "$eof_marker" ]; then
|
|
|
|
track_duration=$(echo "$track_end_s - $track_start_s" | bc)
|
|
|
|
else
|
|
|
|
track_duration=""
|
|
|
|
fi
|
2021-03-27 21:18:08 +01:00
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
run_ffmpeg "${audio_file}" "${track_start_s}" "${track_duration}" "${track_title}.${FORMAT}"
|
2021-03-27 21:18:08 +01:00
|
|
|
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
|
2021-04-05 01:41:16 +02:00
|
|
|
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"
|
2021-03-27 21:18:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if [ $# -lt 1 ]; then
|
|
|
|
usage
|
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
command=$1
|
|
|
|
shift
|
|
|
|
|
2021-04-05 01:41:16 +02:00
|
|
|
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
|
|
|
|
|
2021-04-05 02:33:10 +02:00
|
|
|
# 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"
|
|
|
|
|
2021-03-27 21:18:08 +01:00
|
|
|
case "x-${command}" in
|
|
|
|
x-show)
|
|
|
|
|
|
|
|
# Takes the audio file in first parameter
|
|
|
|
if [ $# -ne 2 ]; then
|
2021-04-05 01:41:16 +02:00
|
|
|
echo "Usage: $0 show music-file time-stamps-file" >&2
|
2021-03-27 21:18:08 +01:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
get_values "$1" "$2"
|
|
|
|
;;
|
|
|
|
|
|
|
|
x-rip)
|
|
|
|
|
|
|
|
# Takes the audio file in first parameter
|
|
|
|
if [ $# -ne 2 ]; then
|
2021-04-05 01:41:16 +02:00
|
|
|
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-04-05 01:41:16 +02:00
|
|
|
|
2021-03-27 21:18:08 +01:00
|
|
|
*)
|
|
|
|
usage 1>&2
|
|
|
|
exit 1
|
|
|
|
esac
|