#!/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(){ local n=0 local v=0 values=$(echo "$*" | sed 's/:/\ /g' | sed "s/^0//") for i in $(reverse_word_order $values); do case $n in 0) v=$(echo "$v + $i " | bc);; 1) v=$(echo "$v + (60 * $i)" | bc);; 2) v=$(echo "$v + (3600 * $i)" | bc);; *) echo "invalid timecode $*"; exit 1;; esac n=$((n+1)) done echo $v } # Get a more usable time representation for the beginning and the end of songs. get_values(){ audio_file="$1" time_file="$2" total_length=$(soxi -D "${audio_file}" | sed "s/\..*//") # integer values only n=0 while read X; do if [ $n -ne 0 ]; then to=$(get_time $X) to_s=$(get_seconds $to) echo -e "$from_s\t$to_s\t$title" fi #echo $X from=$(get_time $X) from_s=$(get_seconds $from) title=$(get_title $X) if [ -z "${WITH_NUMBER}" ]; then : else title="${n}${WITH_NUMBER}${title}" fi n=$(echo $n + 1 | bc) done < "${time_file}" echo -e "$from_s\t$total_length\t$title" } run_ffmpeg(){ local file=$1 local from=$2 local duration=$3 local title=$4 if [ "${SIMULATION}" -eq 1 ]; then [ -z "${QUIET}" ] && echo "ffmpeg -loglevel error -ss '$from' -t '$duration' -i '${file}' '${title}'" else [ -z "${QUIET}" ] && echo "ffmpeg -loglevel error -ss '$from' -t '$duration' -i '${file}' '${title}'" $(< /dev/null ffmpeg -loglevel quiet -ss "$from" -t "$duration" -i "${file}" "${title}") fi } rip(){ n=0 from=0 to=0 audio_file="$1" time_file="$2" [ "$FORMAT" = "" ] && echo "default format: opus" && FORMAT="opus" #echo "from to duration title" get_values "$audio_file" "$time_file" | while read LINE; do from=$(echo $LINE | cut -d ' ' -f 1) to=$(echo $LINE | cut -d ' ' -f 2) title=$(echo $LINE | cut -d ' ' -f 3-) duration=$(echo "$to - $from" | bc) run_ffmpeg "${audio_file}" "${from}" "${duration}" "${title}.${FORMAT}" n=$((n + 1)) done } usage(){ echo "usage: $0 command" echo "command: show " echo "command: rip " 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 [0|1] (do not invoke ffmpeg)" echo "envvar: FORMAT [mp3,ogg,opus,…] (see the ffmpeg documentation)" echo "envvar: WITH_NUMBER [separator] (not null = write song number, with this separator)" echo " example: WITH_NUMBER=_ Song names will be 1_song.opus 2_song.opus…" echo "envvar: QUIET (if set to any value, ffmpeg commands are not displayed)" } if [ $# -lt 1 ]; then usage exit 0 fi command=$1 shift 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" 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" exit 1 fi rip "$1" "$2" ;; *) usage 1>&2 exit 1 esac