diff --git a/get-tracks.sh b/get-tracks.sh index 33f7166..95a6c97 100755 --- a/get-tracks.sh +++ b/get-tracks.sh @@ -1,7 +1,8 @@ #!/usr/bin/env sh -# From a single byte in hexadecimal per line -# to lines ending with 0a (hex for '\n'). +# From a single byte in hexadecimal per line to lines ending with 0a +# (hex for '\n'). Ex: 61 62 63 0a +# Required to easily match (and remove) multi-byte characters. regroup_lines() awk ' BEGIN { line_start=1 @@ -32,25 +33,40 @@ simple_quote() sed "s/e2 80 99/27/g" # From / to '-' replace_slashes() sed "s/2f/2d/g" +remove_backslashes() sed "s/5c//g" + remove_multibyte_characters() sed "s/e2 80 .. //g" +uppercase() tr "[a-z]" "[A-Z]" + +# One column decimal to plain text. +from_dec() awk '{ printf ("%c", $1 + 0) }' + +# Replace spaces by line returns, outputs a single column. +spaces_to_line_returns() tr " " "\n" + # Convert input into hexadecimal and a single byte per line. -to_hex_one_column() xxd -p -c 1 +to_hex_one_column() { od -An -tx1 | awk '{for(i=1;i<=NF;i++){ print $i }}'; } -# Reverse hexadecimal to original value. -from_hex() xxd -p -r +# One column hexa to one column decimal. +hex_to_dec() { { echo "obase=10;ibase=16;" ; cat ; } | bc ; } -# Remove non ascii characters, convert "’" to "'", or remove invalid filename characters. +# Reverse hexadecimal (with space separators) to original value. +from_hex() { spaces_to_line_returns | uppercase | hex_to_dec | from_dec; } + +# Remove non ascii, backslashes and invalid filename characters, +# convert "’" to "'", "/" to " - ". to_ascii(){ - 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 "'". - replace_slashes | # Replace / by ' - ', since it isn't a valid filename character. + to_hex_one_column | # Input to hexadecimal, 1-byte representation per line. + regroup_lines | # From 1-byte to x-byte lines with space separators. + simple_quote | # From "’" to "'". + replace_slashes | # From / to '-'. remove_multibyte_characters | # Remove non ascii values. - from_hex # Convert back from hex. + remove_backslashes | # Can mess with the script. + from_hex # Convert back from hex (x-byte per line, space separator). } -process_end_of_songs() awk -v NONUMBER="$NONUMBER" -v SEPARATOR="$SEPARATOR" ' +comp_end_of_tracks() awk -v NONUMBER="$NONUMBER" -v SEPARATOR="$SEPARATOR" ' BEGIN { OFS=" " } @@ -106,7 +122,7 @@ first_column_to_seconds() awk ' ' # Get a more usable time representation for the beginning and the end of songs. -process_time_file(){ to_ascii | first_column_to_seconds | process_end_of_songs ; } +get_timestamps(){ to_ascii | first_column_to_seconds | comp_end_of_tracks; } run_ffmpeg(){ file=$1 @@ -139,15 +155,15 @@ run_ffmpeg(){ esac if [ "$SIMULATION" = "" ]; then - $(< /dev/null ffmpeg $LOG_LEVEL $FROM $TO -i "$INPUT_FILE" "$OUTPUT_FILE") + ffmpeg $LOG_LEVEL $FROM $TO -i "$INPUT_FILE" "$OUTPUT_FILE" fi } -rip(){ +extraction(){ audio_file="$1" time_file="$2" - process_time_file < "$time_file" | while read LINE; do + get_timestamps < "$time_file" | while read LINE; do track_start=$(echo $LINE | cut -d ' ' -f 1) track_end=$(echo $LINE | cut -d ' ' -f 2) track_title=$(echo $LINE | cut -d ' ' -f 3-) @@ -156,7 +172,12 @@ rip(){ track_end="" fi - run_ffmpeg "${audio_file}" "${track_start}" "${track_end}" "${track_title}.${FORMAT}" + # Input is /dev/null, otherwise subshells will take the output + # of "get_timestamps" as input. + # Be careful: "while read X" is a dangerous shell design. + < /dev/null run_ffmpeg "${audio_file}" \ + "${track_start}" "${track_end}" \ + "${track_title}.${FORMAT}" done } @@ -192,11 +213,6 @@ Environment variables: END } -if [ $# -lt 1 ]; then - usage - exit 0 -fi - header(){ if [ "$HEADERS" = "1" ]; then echo $* @@ -237,20 +253,9 @@ if [ "$SIMULATION" != "" ]; then header "SIMULATION envvar is set: this is a simulation." fi -/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 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 $# in - 1) process_time_file < "$1" ;; - 2) rip "$1" "$2" ;; + 0) usage; exit 0;; + 1) get_timestamps < "$1" ;; + 2) extraction "$1" "$2" ;; *) usage 1>&2 ; exit 1 ;; esac