/*
* ICY (I Can Yell) aka SHOUTcast client
*
* Metadata goes to standard error. MP3 data to standard output.
* Pipe to a MP3 decoder:
* icy http://... | games/mp3dec
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
typedef struct Icy Icy;
struct Icy {
Biobuf *bi, *bo;
//int status;
//char *name;
//char *genre;
//char *url;
//int pub;
//int br;
int metaint;
};
Biobuf icybin, icybout;
Icy icymeta;
void*
emalloc(ulong size)
{
void *p;
p = malloc(size);
if(p == nil)
sysfatal("malloc failed: %r");
return p;
}
Icy*
icyinit(int fd, char *path)
{
char *line;
Icy *icy;
Biobuf *bi, *bo;
icy = &icymeta;
icy->bi = bi = &icybin;
icy->bo = bo = &icybout;
Binit(bi, fd, OREAD);
Binit(bo, fd, OWRITE);
Bprint(bo, "GET /%s\r\n"
"User-Agent: icy/0.1\r\n"
"Icy-MetaData:1\r\n"
"\r\n", path);
Bflush(bo);
icy->metaint = 0;
while((line = Brdstr(bi, '\n', 1)) != nil){
if(Blinelen(bi) > 0 && line[Blinelen(bi)-1] == '\r')
line[Blinelen(bi)-1] = 0;
if(line[0] == 0)
break;
fprint(2, "%s\n", line);
if(strncmp(line, "icy-metaint:", 12)==0)
icy->metaint = atoi(line+12);
free(line);
}
return icy;
}
void
printtitle(Icy *icy)
{
int len, n;
char *title;
len = Bgetc(icy->bi);
if(len <= 0)
return;
len *= 16;
title = emalloc(len+1);
n = Bread(icy->bi, title, len);
if(n <= 0){
free(title);
return;
}
title[n] = 0;
fprint(2, "%s\n", title);
free(title);
}
void
parseurl(char *url, char **host, char **port, char **path)
{
char *h, *s, *p;
if(strncmp(url, "http://", 7) != 0)
sysfatal("bad url");
h = url+7;
s = strchr(h, ':');
p = strchr(h, '/');
if(s == nil || s > p)
s = "80";
else
*s++ = 0;
if(p == nil)
p = "";
else
*p++ = 0;
if(h[0] == 0 || h[0] == 0)
sysfatal("bad host/port");
*host = h;
*port = s;
*path = p;
}
void
main(int argc, char *argv[])
{
int fd, n, title;
Icy *icy;
uchar *data;
char *host, *port, *path;
ARGBEGIN{
}ARGEND
if(argc < 1){
fprint(2, "usage: ice url\n");
exits("usage");
}
parseurl(argv[0], &host, &port, &path);
fd = dial(netmkaddr(host, "tcp", port), 0, 0, 0);
if(fd < 0)
sysfatal("dial: %r");
icy = icyinit(fd, path);
title = 1;
if(icy->metaint <= 0)
title = 0;
data = emalloc(icy->metaint);
for(;;){
n = Bread(icy->bi, data, icy->metaint);
if(n <= 0)
break;
write(1, data, n);
if(title)
printtitle(icy);
}
if(n < 0)
sysfatal("read: %r");
free(data);
close(fd);
exits(nil);
}
|