get-tracks/get-tracks.sh

284 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env sh
regroup_lines(){
awk '
BEGIN {
first=1
}
{
if (first == 1)
line = $1;
else
line = line " " $1;
first = 0;
if ($1 == "0a") {
print line;
first = 1
}
}
END {
if (first == 0)
print line
}
'
}
simple_quote(){
sed "s/e2 80 99/27/g"
}
remove_multibyte_characters(){
sed "s/e2 80 .. //g"
}
to_hex_one_colomun(){
xxd -p -c 1
}
from_hex(){
xxd -p -r
}
to_ascii(){
to_hex_one_colomun |
regroup_lines |
simple_quote |
remove_multibyte_characters |
from_hex
}
process_durations(){
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;
}
'
}
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;
}
'
}
# Get a more usable time representation for the beginning and the end of songs.
process_time_file(){
time_file="$1"
to_ascii < "$time_file" | first_column_to_seconds | process_durations
}
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"
process_time_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" != "END_OF_FILE" ]; 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 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)"
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"
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
# 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
</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
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
process_time_file "$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"
;;
x-input)
to_ascii < "$1"
;;
*)
usage 1>&2
exit 1
esac