4
# Copyright (c) 2003-2006 Gil Megidish
4
# Copyright (c) 2003-2008 Gil Megidish
6
6
# Formatted filename patch by Sean Dague (13 Dec 2005)
7
# Modified by Cristian Greco 2008 (release 1.3)
8
# This program is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU General Public License
10
# as published by the Free Software Foundation; either version 2
11
# of the License, or (at your option) any later version.
9
# This program is free software; you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation; either version 2 of the License, or
12
# (at your option) any later version.
13
14
# This program is distributed in the hope that it will be useful,
14
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
17
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
# You should have received a copy of the GNU General Public License along
20
# with this program; if not, write to the Free Software Foundation, Inc.,
21
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28
my $def_agent = "icecream/1.2";
29
my $version = "icecream/1.2";
29
my $def_agent = "icecream/1.3";
30
my $version = "icecream/1.3";
30
31
my $accept_header = "audio/mpeg, audio/x-mpegurl, audio/x-scpls, */*";
32
33
my $def_timeout = 500;
335
343
sub get_302_location
337
345
my ($message) = shift || return undef;
338
my ($headers, $body);
340
($headers, $body) = split("\r\n\r\n", $message, 2);
341
return undef unless defined $headers;
343
if ($headers =~ /\nLocation:\s*(.+)\n/i)
347
if ($message =~ /.*Location:\s*(.+)\n/i)
641
644
$trackid = sprintf "%02d - ", $context->{id};
644
my $fn = $trackid . $context->{title} . '.mp3';
647
my $fn = $trackid . $context->{title};
648
$fn .= defined $context->{'is-ogg'} ? ".ogg" : ".mp3";
645
649
return unless open_output($context, $fn);
804
811
check_stop_cond();
805
last if ($config->{stop} != 0);
812
last if ((defined $config->{stop}) && ($config->{stop} != 0));
807
814
my $chunk = recv_chunk($sock, $stream->{'metaint'});
808
815
if (length($chunk) < $stream->{'metaint'})
852
860
debug("loop_anonymous_stream()");
854
862
$context->{id} = 0;
855
$context->{title} = $stream->{name};
863
$context->{title} = defined $stream->{name} ? $stream->{name} : 'stream-' .time;
856
864
$context->{length} = 0;
857
865
$context->{output_open} = 0;
866
$context->{'is-ogg'} = $stream->{'is-ogg'};
861
870
check_stop_cond();
862
last if ($config->{stop} != 0);
871
last if ((defined $config->{stop}) && ($config->{stop} != 0));
864
873
my $chunk = recv_chunk($sock, 1024);
865
874
last unless length($chunk) > 0;
977
987
my $agent = $config->{'user-agent'};
978
988
my $request = "GET $path HTTP/1.0\r\n" .
989
"Host: $host:$port\r\n" .
990
"Accept: ${accept_header}\r\n" .
979
991
"Icy-MetaData:1\r\n" .
980
992
"User-Agent:$agent\r\n" .
1014
elsif ($status == 302)
1005
1017
$location = get_302_location($headers);
1020
elsif ($status == 400)
1012
1023
print STDERR "error: server is full (use --debug for complete response)\n";
1027
elsif ($status != 200)
1018
1029
# nothing works fine these days
1019
1030
print STDERR "error: server error $status (use --debug for complete response)\n";
1023
1034
} while ($status != 200);
1025
if ($headers =~ /^HTTP/)
1027
# ICY is embedded inside an HTTP
1028
$headers = slurp_headers($sock);
1029
return 0 unless defined $headers;
1032
my $raw_stream_data = parse_stream_headers($headers);
1033
if (! defined $raw_stream_data)
1035
print STDERR "error: problems parsing stream headers (please use --debug)\n";
1039
my $stream_data = prepare_stream_data($raw_stream_data);
1040
if (! defined $stream_data->{'name'})
1042
print STDERR "error: not an icecast/shoutcast stream\n";
1046
if ($config->{debug})
1048
my $info = "name: $stream_data->{name}\n";
1049
$info .= "genre: $stream_data->{genre}\n" if defined $stream_data->{genre};
1050
$info .= "metaint: $stream_data->{metaint}\n" if defined $stream_data->{metaint};
1051
debug("parsed stream headers", $info);
1036
# manage icy and x-audiocast headers even if they are embedded in http
1037
# but skip header manipulation in other cases!
1038
if (($headers =~ /.*icy.*/) or ($headers =~ /.*audiocast.*/))
1040
my $raw_stream_data = parse_stream_headers($headers);
1041
if (! defined $raw_stream_data)
1043
print STDERR "error: problems parsing stream headers (please use --debug)\n";
1047
$stream_data = prepare_stream_data($raw_stream_data);
1048
if (! defined $stream_data->{'name'})
1050
print STDERR "error: not an icecast/shoutcast stream\n";
1054
if ($config->{debug})
1056
my $info = "name: $stream_data->{name}\n";
1057
$info .= "genre: $stream_data->{genre}\n" if defined $stream_data->{genre};
1058
$info .= "metaint: $stream_data->{metaint}\n" if defined $stream_data->{metaint};
1059
debug("parsed stream headers", $info);
1062
if ($headers =~ /.*Content-Type: application\/ogg/i)
1064
# streaming url is .ogg file,
1065
# remember this when saving output file
1066
$stream_data->{'is-ogg'} = 1;
1054
1070
if (defined $stream_data->{'metaint'})
1056
1072
# server periodically sends stream title
1080
1096
print " -q, --quiet no printouts\n";
1081
1097
print " -v, --verbose be verbose\n";
1082
1098
print " -t, --tracks split into tracks when saving\n";
1083
print " --name=NAME output stream to file NAME. Format codes\n";
1099
print " --name=NAME save stream to file NAME. Format codes\n";
1084
1100
print " are replaced as in the date command.\n";
1085
print " --stdout output tracks to stdout (implies quiet)\n";
1101
print " --stop=N[units] stop download after N (kb, mb, min, songs)\n";
1102
print " --user-agent=AGENT identify as AGENT stead of ${def_agent}\n";
1103
print " --stdout output stream to stdout (implies quiet)\n";
1086
1104
print " --sync sync mpeg audio\n";
1087
print " --stop=N[units] stop after N (kb, mb, min, songs)\n";
1088
1105
print " --debug turn on debugging\n";
1089
print " --useragent=AGENT identify as AGENT stead of ${def_agent}\n";
1182
1198
my ($url) = shift || return undef;
1183
1199
my ($config) = shift || return undef;
1201
# play direct stream url (not .pls nor .m3u)
1202
if (($url =~ /^http/) and (not (($url =~ /\.m3u$/) or ($url =~ /\.pls$/))))
1185
1208
my $raw = retreive_playlist($url);
1186
1209
if (! defined $raw)
1293
1317
=head1 DESCRIPTION
1295
icecream is a non-interactive stream download utility. It connects
1296
to icecast and shoutcast servers and redirects all fetched content
1297
to an stdin-capable player or to media files on your disk. With an
1298
option turned on, it can save the stream into different files, each
1299
representing the played track. It is also possible to tee the input
1300
to both disk and stdout.
1319
icecream is a lightweight, non-interactive, stream download utility.
1320
It connects to icecast and shoutcast servers or direct stream URLs, and
1321
redirects all fetched content to stdout and/or to media files on your disk.
1323
Listen to the stream piping the output to a stdin-capable media player.
1324
Save the stream to a named file or split it into different tracks.
1325
It is possible to redirect the stream and save it to disk at the same time.
1327
icecream is able to parse pls and m3u playlists, and to download mp3 and ogg
1328
direct stream URLs. If the stream is anonymous it will be saved as
1329
'stream-time.mp3', where time is actual timestamp.
1320
Output stream to stdout (implies -q)
1322
1347
=item B<-t>, B<--tracks>
1324
1349
Split stream into tracks (if possible)
1326
1351
=item B<--name=NAME>
1328
Output stream to file specified by NAME. Format codes starting
1329
with "%" will be replaced. See the date command for valid
1353
Save the stream to file specified by NAME. Format codes starting with "%" will
1354
be replaced. See the date command for valid format codes.
1332
1356
=item B<--stop=N[units]>
1334
Stop stream after N minutes, song or KB/MB transferred
1358
Stop downloading the stream after N kb/mb/min/songs
1360
=item B<--user-agent=AGENT>
1362
Set user-agent header to AGENT
1366
Output stream to stdout (implies -q)
1370
Turn syncing on, required for some mpeg players that read from stdin
1336
1372
=item B<--debug>
1338
1374
Turn on debugging outputs
1340
=item B<--useragent=AGENT>
1342
Set useragent header to AGENT
1346
Turn syncing on, required for some mpeg players that read from stdin
1354
1383
=item Streaming to mpg123
1356
icecream -s http://radio.com/playlist.pls | mpg123 -
1385
icecream --stdout http://radio.com/playlist.pls | mpg123 -
1358
1387
=item Split stream into different tracks
1360
1389
icecream -t http://metal.org/radio.pls
1391
=item Split stream into tracks and play with vlc at the same time
1393
icecream -t --stdout http://streaming.com/playlist.pls | vlc file:/dev/stdin
1362
1395
=item Prepare a 74 minute CD
1364
1397
icecream -t --stop 74min http://trace.net/playlist.m3u
1366
1399
=item Use a filename with today's date as output
1368
icecream -q --name 'radio_%Y_%m_%d' --stop 60min
1369
http://radio.com/playlist.pls
1401
icecream -q --name 'radio_%Y_%m_%d' --stop 60min http://radio.com/playlist.pls
1375
You are welcome to send bug reports about icecream to our mailing
1376
list. Feel free to visit http://icecream.sourceforge.net
1407
You are welcome to send bug reports about icecream to our mailing list.
1408
Feel free to visit http://icecream.sourceforge.net