gpz500’s Weblog

15 Giugno 2009

Salvare gli stream RealAudio in MP3

audiobook

Un amico mi ha fatto conoscere la possibilità di scaricare e salvare gli audiolibri che si possono ascoltare (in diretta) su Rai Radio Tre durante la trasmissione Ad alta voce, e (poi) in streaming sul sito web della Rai. Si tratta di grandi classici della letteratura internazionale letti da “voci capaci”, ognuno costituito da 15/20 puntate.

Visto che scaricare e convertire in MP3 una puntata alla volta era veramente noioso ho scritto uno script bash che, dato l’indirizzo di una pagina web che contiene più link a degli stream RealAudio (come le pagine della trasmissione Ad alta voce), scarica e converte automaticamente e in parallelo tutti gli stream citati.

Lo script in questione l’ho battezzato, con ben poca fantasia, savera (SAVE RealAudio). Per poterlo utilizzare è necessario avere installati, e disponibili nel PATH di sistema, i comandi curl, mplayer, lame (per output MP3) e/o ffmpeg (per il formato AAC), oltre che, naturalmente, la shell Bash. Io l’ho testato su Linux e Mac OS X ma non è escluso che, una volta installati i programmi richiesti, funzioni anche su Windows con Cygwin.

Installazione su Ubuntu Linux

Vista la grande diffusione, le istruzioni riportate sono per Ubuntu/Debian ma non sarà difficile adattarle anche a distribuzioni diverse.

  1. Installare i programmi necessari con il seguente comando dato da terminale:
    $ sudo apt-get install curl mplayer lame ffmpeg
  2. scaricare lo script da qui:
  3. spostarlo in una delle cartelle che fanno parte della variabile di ambiente PATH. Ottime scelte sono /usr/local/bin (per un’installazione di sistema) e /home/<nomeutente>/bin (solo per l’utente <nomeutente>) perché non vengono gestite dal sistema di pacchettizzazione della distribuzione e quindi non si genera alcun conflitto;
  4. attivare i permessi di esecuzione con il comando
    $ sudo chmod +x /path/to/savera

Installazione su Mac OS X

Procurarsi tutti i programmi necessari su Mac OS X è decisamente più laborioso che su Linux in quanto i vari software hanno origini diverse e si installano in modo diverso l’uno dall’altro: curl fa eccezione perché è preinstallato (almeno su Leopard), mplayer si trova come binario precompilato, lame si trova su Fink (ma non in forma binaria) e di ffmpeg si trovano solo i sorgenti. Per chi ha capito al volo questo paragrafo non resta che installare il software e provare lo script. Per tutti gli altri, non è escluso che, prima o poi, realizzi un pacchetto complessivo con tutto il software necessario (magari con un’interfaccia in AppleScript).

Uso

Lo script crea i file MP3/AAC nella cartella corrente, quindi va lanciato in una cartella creata appositamente allo scopo. Ad esempio

$ mkdir -p ~/Musica/Audiolibri/Lolita
$ cd ~/Musica/Audiolibri/Lolita

A questo punto è sufficiente lanciare savera con argomento il link alla pagina dell’audiolibro che si vuol salvare (il formato di default è Mp3):

$ savera http://www.radio.rai.it/radio3/terzo_anello/alta_voce/archivio_2004/eventi/2004_06_01_lolita/index.cfm

I tipi di URL accettati da savera sono:

  • l’URL http://… di una pagina html che contiene i link a uno o più stream (come nel caso degli audiolibri RAI);
  • l’URL http://… di un file .ram (playlist di RealPlayer)
  • l’URL rtsp://… di uno stream RealAudio.

Una volta lanciato, savera scaricherà e convertirà – in parallelo – tutte le sorgenti indicate e tornerà al prompt dei comandi solo dopo aver terminato. Il tempo impiegato dipende dal numero di stream, dalla velocità del vostro collegamento ad Internet, dalla potenza di calcolo del vostro computer; se si ha una connessione ADSL sufficientemente veloce e un computer abbastanza potente, il tempo di conversione dipenderà unicamente dalla durata della puntata più lunga, in quanto l’audio viene comunque trasferito in tempo reale.

Ci sono alcune opzioni che si possono scegliere la cui documentazione viene visualizzata con l’opzione -h:

$ savera -h

Appendice: lo script

Segue il contenuto dello script:

#!/bin/bash
#
# Save to MP3 or AAC files RealAudio streams extracted from web pages or directly
# supplied. An example are the audiobook streams from the Italian state
# Broadcasting Service (RAI) radio programme "Il terzo anello" at
# http://www.radio.rai.it/radio3/terzo_anello/alta_voce/archivio_2009/eventi/2009_01_12_diceriadelluntore/index.cfm
#
# Thanks to Alessandro Meiattini (http://www.meiaweb.com/).
#
# Copyright (C) - 2009
# Alessandro Morgantini - gpz500 at technologist dot com
#
# Released under the terms of GPL2 (http://www.gnu.org/licenses/gpl-2.0.html).
# Modified on $Date: 2009-07-03 19:48:36 +0200 (Ven, 03 Lug 2009) $
# SVN $Revision: 61 $
#set -x

# Defaults
DEFAULT_CODEC="MP3"
DEFAULT_MAX_NPROC=30

CODEC=""
COMMAND_NAME=$(basename $0)
ARG_URLS=""
MAX_NPROC=0
NPROC=0
POOL=""
URLS=""
USAGE="Usage: ${COMMAND_NAME} [options] URL [URL ...]
Save to MP3 or AAC files the RealAudio streams (.ram files) from web pages

Accepted options:
  -h, --help          Print this help
  -m, --mp3           Select MP3 as output format (default)
  -a, --aac           Select AAC as output format
  -n, --nocodec       Save the streams with no conversion
  -j, --jobs=N        Set the parallelism degree to N ($DEFAULT_MAX_NPROC by default)

Valid URLs are:
  an http://... web page wich contains links to .ram playlists;
  an http://...ram playlist;
  an rtsp://...ra RealAudio stream.

E.g.:
$COMMAND_NAME http://www.radio.rai.it/radio3/terzo_anello/alta_voce/archivio_2009/eventi/2009_01_12_diceriadelluntore/index.cfm"
TEMP_FILES=""

# Return on the standard output the extension part (the part after the last
# period) of the argument
get_extension ()
{
	NAME=$(basename $1)
	if echo "$NAME" | grep "\." >/dev/null; then
		echo -n "$NAME" | sed 's/^.*\.\([^\.]*\)$/\1/'
	else
		echo -n ""
	fi
}

# Add a process to the pool
add_to_pool ()
{
	POOL="$POOL $1"
	NPROC=$(($NPROC + 1))
}

# Remove from the pool the terminated processes
update_pool ()
{
	local OLDPOOL="$POOL"
	local PID
	POOL=""
	NPROC=0
	for PID in $OLDPOOL; do
		ps $PID | grep $PID >/dev/null
		if [[ $? -eq 0 ]]; then
			add_to_pool $PID
		fi
	done
}

# Check for terminated processes in the pool
check_pool ()
{
	local OLDPOOL="$POOL"
	local PID
	for PID in $OLDPOOL; do
		ps $PID | grep $PID >/dev/null
		if [[ $? -ne 0 ]]; then
			update_pool
			break
		fi
	done
}

# Command line parsing
while [ -n "$1" ]; do
	case "$1" in
		--help|-h)
			echo "$USAGE"
			exit 0
			;;
		--mp3|-m)
			if [ -z "$CODEC" ]; then
				CODEC="MP3"
			else
				echo "$COMMAND_NAME error: you can't specify more than one output format" >&2
				echo "$USAGE" >&2
				exit 1
			fi
			shift
			;;
		--aac|-a)
			if [ -z "$CODEC" ]; then
				CODEC="AAC"
			else
				echo "$COMMAND_NAME error: you can't specify more than one output format" >&2
				echo "$USAGE" >&2
				exit 1
			fi
			shift
			;;
		--nocodec|-n)
			if [ -z "$CODEC" ]; then
				CODEC="NONE"
			else
				echo "$COMMAND_NAME error: you can't specify more than one output format" >&2
				echo "$USAGE" >&2
				exit 1
			fi
			shift
			;;
		-j)
			if [ $MAX_NPROC -eq 0 ]; then
				shift
				MAX_NPROC=$1
			else
				echo "$COMMAND_NAME error: you can't specify more than one -j or --jobs option" >&2
				echo "$USAGE" >&2
				exit 1
			fi
			shift
			;;
		--jobs*)
			if [ $MAX_NPROC -eq 0 ]; then
				MAX_NPROC=$(echo "$1" | cut -d = -f 2)
			else
				echo "$COMMAND_NAME error: you can't specify more than one -j or --jobs option" >&2
				echo "$USAGE" >&2
				exit 1
			fi
			shift
			;;
		-*)
			echo "$COMMAND_NAME error: option \"$1\" unkown" >&2
			echo "$USAGE" >&2
			exit 2
			;;
		*)
			ARG_URLS="$ARG_URLS $1"
			shift
			;;
	esac
done

# Preliminary checks
if [ -z "$(which mplayer)" ]; then
	echo "Sorry: you must have mplayer installed." >&2
	exit 1
fi
if [ -z "$(which curl)" ]; then
	echo "Sorry: you must have curl installed." >&2
	exit 1
fi
if [ -z "$CODEC" ]; then
	CODEC="$DEFAULT_CODEC"
fi
echo "$COMMAND_NAME: the output format is $CODEC"
if [ "$CODEC" = "MP3" -a -z "$(which lame)" ]; then
	echo "Sorry: you must have lame installed." >&2
	exit 1
elif [ "$CODEC" = "AAC" -a -z "$(which ffmpeg)" ]; then
	echo "Sorry: you must have ffmpeg installed." >&2
	exit 1
fi
if [ $MAX_NPROC -eq 0 ]; then
	MAX_NPROC=$DEFAULT_MAX_NPROC
fi
echo "$COMMAND_NAME: the parallelism degree is $MAX_NPROC"
if [ -z "$ARG_URLS" ]; then
	echo "$COMMAND_NAME error: you must specify at least a valid URL" >&2
	echo "$USAGE" >&2
	exit 4
fi

# Retrieving URLs
for URL in $ARG_URLS; do
	if echo "$URL" | grep "^rtsp://.*"; then
		URLS="$URLS $URL"
	elif echo "$URL" | grep "^http://.*\.ram$"; then
		URLS="$URLS $(curl -s $URL | cat -v | sed 's/\^M$//')"
	elif echo "$URL" | grep "^http://.*"; then
		INPUTFILE=$(mktemp)
		curl -s "$URL" | grep "http://.*\.ram" | sed "s/^.*\(http:\/\/.*\.ram\).*$/\1/" >"$INPUTFILE"
		while read RAM; do
			URLS="$URLS $(curl -s $RAM | cat -v | sed 's/\^M$//')"
		done &2
		exit 1
	fi
done

# Check if we are behind a proxy
if [ -n "$http_proxy" ]; then
	echo "$COMMAND_NAME: sorry. Because of mplayer, $COMMAND_NAME can't work behind an http proxy."
	echo "In case you know out to use them, the URLs are saved in the file ra_urls.txt"
	[ -e ra_urls.txt ] && rm ra_urls.txt
	for URL in $URLS; do
		echo $URL >>ra_urls.txt
	done
	exit 0
fi

# Set the SIGINT handler
clean_on_exit ()
{
	for file in $TEMP_FILES; do
		rm -f "$file"
	done
}
trap clean_on_exit SIGINT

# Download the streams
for URL in $URLS; do
	EXT=$(get_extension "$URL")
	FILENAME=$(basename "$URL" | sed 's/\.'$EXT'$//')
	if [ "$CODEC" = "NONE" ]; then
		mplayer -quiet -noframedrop -dumpfile "$FILENAME.$EXT" -dumpstream "$URL" &
	else
		mkfifo "$FILENAME.wav" && TEMP_FILES="$TEMP_FILES $FILENAME.wav"
		mplayer -quiet -noframedrop -ao pcm:file="$FILENAME.wav" "$URL" &
		if [ "$CODEC" = "MP3" ]; then
			lame --quiet "$FILENAME.wav" "$FILENAME.mp3" &
		else
			ffmpeg -i "$FILENAME.wav" -acodec libfaac -ab 128k -f aac "$FILENAME.m4a" &
		fi
	fi
	add_to_pool $!
	while [ $NPROC -ge $MAX_NPROC ]; do
		check_pool
		sleep 0.5
	done
done
wait

# Delete all intermediate files
clean_on_exit
echo "All done!"

6 Commenti »

  1. Questo post è davvero interessante. Complimenti! Erano mesi che stavo cercando su internet qualcosa che mi aiutasse a trasformare in mp3 gli stream RAM, quindi ero tutto contento quando mi sono accorto di essere fra quelli che usa mac osx e non ha capito al volo la parte di lame.
    Visto che l’hai anche già ipotizzato, ti prego di realizzare il pacchetto complessivo con tutto il software necessario (magari con un’interfaccia in AppleScript)!!!
    In ogni caso, complimenti e grazie. Ciao, g.

    Commento di leleatma — 8 Settembre 2009 @ 22:40 | Replica

  2. Molto interessante, complimenti. Per scaricare i podcast delle passate trasmissioni del programma radiofonico “Ad alta voce” è possibile collegarsi al forum:
    http://podcasthall.forumcommunity.net/
    e scaricarli gratuitamente

    Commento di Daniele — 22 Settembre 2009 @ 13:16 | Replica

    • …. mi sembra un ottimo consiglio per chi non è ancora così addentro al linguaggio di programmazione.
      Inoltre ho visto che ci sono un sacco di altre cose interessantissime!
      Grazie

      Commento di Lea — 29 Ottobre 2009 @ 16:21 | Replica

  3. Bravo, complimenti. Sono anch’io un fanatico di ad “altavoce”. In passato i file erano dati direttamente in MP3 ora invece in CFM e per un non addetto ai lavori non è facile convertirli. Muoio dalla voglia di farmi un CD di Pinocchio e dell’Isola di Arturo che stanno leggendo in questi giorni. Ho un Mac ma non so seguire le tue istruzioni. Aspetto pertanto con ansia che tu realizzi al più presto il pacchetto complessivo. Diventeresti un beneffattore della cultura e meriteresti il Nobel.
    Con affetto,

    Paolo

    Commento di paolo — 28 Settembre 2009 @ 13:50 | Replica

    • Purtroppo il progetto di fare un’interfaccia grafica per Mac OS X langue…
      Se hai un Mac con processore Intel penso che la via più rapida sia installare un programma di virtualizzazione (VirtualBox è gratis e va benissimo…), all’interno di questo installare Ubuntu Linux e quindi seguire le istruzioni per Ubuntu…

      Commento di gpz500 — 28 Settembre 2009 @ 20:57 | Replica

  4. Anch’io ho apprezzato davvero molto questo script, che dovrebbe risolvere un bel po’ di problemi che mi si sono sempre presentati per salvare le serie di Ad Alta Voce.

    Purtroppo, pero’, vedo che lo script (uso debian squeeze) dopo qualche secondo si interrompe sempre con Segmentation fault e non riesco proprio a capire perche’.
    Ecco i messaggi:

    kir@papaya:~/bin$ ./savera –jobs=2 “http://www.radio.rai.it/radio3/terzo_anello/alta_voce/archivio_2009/eventi/2009_09_01_lisoladiarturo/index.cfm”
    savera: the output format is MP3
    savera: the parallelism degree is 2
    http://www.radio.rai.it/radio3/terzo_anello/alta_voce/archivio_2009/eventi/2009_09_01_lisoladiarturo/index.cfm
    ./savera: line 232: 24210 Segmentation fault mplayer -quiet -noframedrop -ao pcm:file=”$FILENAME.wav” “$URL”
    ./savera: line 232: 24223 Segmentation fault mplayer -quiet -noframedrop -ao pcm:file=”$FILENAME.wav” “$URL”

    Qualcun altro ha avuto errori simili?
    Grazie in anticipo e saluti a tutti.

    Commento di kir — 12 Ottobre 2009 @ 12:32 | Replica


RSS feed dei commenti a questo articolo. TrackBack URI

Lascia un commento

Blog su WordPress.com.