#!/usr/bin/perl
#
# Get a RealAudio stream and transcode it to MP3 for offline listening.
# (c) Andrew Flegg 2005. Released under the Artistic Licence.
# http://www.bleb.org/software/
#
# Syntax:  ra2mp3 [<options>] <URL> [<outfile>]
#    -m, --mono                 Produce a mono MP3
#    -b, --bitrate=BITRATE      Set the bitrate of the MP3 (default: 192)
#    -o, --offset=SECOND        Skip the first SECOND seconds
#    -q, --quiet                Be vewwy vewwy quiet
#    -t, --title=TITLE          Override the resulting title ID3 tag
#    -a, --author=AUTHOR        Override the resulting author ID3 tag
#    -c, --comment=COMMENT      Override the resulting comment ID3 tag
#
# If output filename is prefixed with 'scp:', the result is copied to the
# remote machine using scp.
#
# Examples:
#   ra2mp3 -m -b 48 -o 7230 http://www.bbc.co.uk/radio/aod/shows/rpms/radio4/today.ram scp:website.somehost.com:public_html/misc/Today.mp3
#   ra2mp3 http://www.bbc.co.uk/radio4/hitchhikers/media/discovery.ram

use warnings;
use strict;
use Getopt::Long;
use LWP::Simple;
use File::Temp qw(tempfile);
use File::Basename qw(basename);
use vars qw($CACHE $FREQ $LAME $QUIET);

$CACHE = 128;
$FREQ  = 44.1;
$QUIET = 0;

my %options = ();
GetOptions(\%options, "help|?",
                      "mono|m",
                      "quiet|q",
                      "bitrate|b:i",
                      "title|t:s",
                      "author|a:s",
                      "comment|c:s",
                      "offset|o:i");
die <<EOM if $options{"help"} or not @ARGV;
ra2mp3 [options] <URL> [<outfile>]       (c) Andrew Flegg 2005.
~~~~~~                                   Released under the Artistic Licence
Options:
    -h, --help               This message
    -b, --bitrate=BITRATE    Set the bitrate of the MP3 (default: 192)
    -o, --offset=SECOND      Skip the first SECOND seconds
    -t, --title=TITLE        Override the resulting title ID3 tag
    -a, --author=AUTHOR      Override the resulting author ID3 tag
    -c, --comment=COMMENT    Override the resulting comment ID3 tag
    -q, --quiet              Be vewwy vewwy quiet

If outfile is prefixed with 'scp:' the path will be passed to SCP.

Please report bugs to <andrew\@bleb.org>. Thanks.

EOM

$options{"offset"}  ||= 0;
$options{"bitrate"} ||= 192;
$QUIET = defined($options{'quiet'});

# -- Get the rtsp:// URL if this is a playlist ----------------
#
my $url = $ARGV[0];
if ($url =~ /^\w+tp:.*\.ram$/i) {
    $url = get($url);
} elsif (-f $url and $url =~ /\.ram$/i) {
    die "Unable to handle local playlists (yet).";
}

# -- Add the offset -------------------------------------------
#
if ($options{"offset"}) {
    $url  =~ s/[\?\&]start=[^&=]+//i;
    $url .= ($url =~ /\?/ ? '&' : '?');
    $url .= 'start='.$options{'offset'};
}

# -- Fetch the file using mplayer -----------------------------
#
my ($out, $outFile) = tempfile( "ra2mp3-XXXX", SUFFIX => '.pipe.wav', DIR => '/tmp');
$out->close();
unlink $outFile;
system('/bin/mknod', $outFile, 'p');

open(IN, "mplayer -ao pcm -aofile $outFile -vo null -quiet -noconsolecontrols -cache $CACHE \Q$url\E 2>&1|") or die "Unable to open mplayer: $!\n";
my $inInfo = 0;
my %data   = ( name    => $options{'title'},
               author  => $options{'author'},
               comment => $options{'comment'} );
while(<IN>) {
    next if /Cache fill/i;
    print unless $QUIET;
    last if /Starting playback/i;
    
    $inInfo ||= /Clip info:/;
    next unless $inInfo;
    last if /=====+/;
    next unless /^\s*(\w+):\s*(.*?)\s*$/;

    $data{$1} ||= $2;
    #print "+++ Set '$1' to '$2'\n";
}

# -- Determine MP3 file name ----------------------------------
#
my $mp3File = $ARGV[1];
unless ($mp3File) {
  if ($data{'name'}) {
    $mp3File = $data{'name'}.'.mp3';
  } else {
    $mp3File      = basename($ARGV[0]);
    $mp3File      =~ s/\.\w+$//;
    $data{'name'} = $mp3File;
    $mp3File     .= '.mp3';
  }
}

my $remote  = '';
if ($mp3File =~ s/^scp://) {
    $remote = $mp3File;
    my $mp3;
    ($mp3, $mp3File) = tempfile("ra2mp3-XXXX", SUFFIX => '.mp3', DIR => '/tmp');
    $mp3->close();
}

my $mode  = ($options{'mono'} ? 'm' : 'j');
my $child = fork();

if ($child == 0) {
  exec('lame','-b',$options{'bitrate'},'-m',$mode,'--resample',$FREQ,
         ($QUIET ? '--quiet' : ''),
         $data{'name'} ? ('--tt', $data{'name'}) : (),
         $data{'author'} ? ('--ta', $data{'author'}) : (),
         $data{'copyright'} ? ('--tc', $data{'copyright'}) : (),
       $outFile, $mp3File) == 0 or die "LAME failed: $!\n";
}

wait;
unlink $outFile;

# -- Copy elsewhere if required...
#
if ($remote) {
  system("scp $mp3File $remote ".($QUIET ? '1>/dev/null' : ''));
  unlink $mp3File;
}

print "$data{name} transcoding complete.\n";
exit;
