Skip to content

Instantly share code, notes, and snippets.

@TooTallNate
Last active December 23, 2015 21:29
Show Gist options
  • Save TooTallNate/6696160 to your computer and use it in GitHub Desktop.
Save TooTallNate/6696160 to your computer and use it in GitHub Desktop.
Server that connects to 107.7 THE BONE's online radio station FLV stream, decodes it, and re-broadcasts it as an Icecast server.
/**
* Module dependencies.
*/
var inflect = require('i')();
var flv = require('flv');
var http = require('http');
var icecast = require('icecast');
var url = process.argv[2] || 'http://7269.live.streamtheworld.com/KSANFMAAC';
/**
* Connect to the radio station stream over HTTP
*/
var aac;
var decoder;
var currentTrack;
http.get(url, function (res) {
decoder = new flv.Decoder();
decoder.on('metadata', function (name, data) {
console.error('metadata: %j', name, data);
if (name == 'onCuePoint') {
currentTrack = data;
}
});
decoder.on('audio', function (audio) {
console.error('audio event');
aac = audio;
// allow the radio station response stream to flow, even when
// there's no listeners connected to the Icecast server portion...
aac.resume();
});
res.pipe(decoder);
});
/**
* Create Icecast server.
*/
http.createServer(function (req, res) {
console.error(req);
res.setHeader('Content-Type', 'audio/x-aac');
var metaint = 10000;
var acceptsMetadata = req.headers['icy-metadata'] == 1;
if (acceptsMetadata) {
res.setHeader('icy-metaint', metaint);
var writer = new icecast.Writer(metaint);
writer.pipe(res);
res = writer;
if (currentTrack) {
res.queue({ StreamTitle: title(currentTrack) });
}
decoder.on('metadata', function (name, data) {
if (name == 'onCuePoint') {
res.queue({ StreamTitle: title(data) });
}
});
}
aac.pipe(res);
}).listen(8888, function () {
var port = this.address().port;
console.log('107.7 THE BONE Icecast relay server listening on port %d', port);
});
/**
* Returns a formatted "<artist> - <name>" title string for the
* Icecast metadata StreamTitle to use.
*
* @param {Object} data Parsed FLV "metadata" event data object
* @return {String} "title" string to send to the Icecast client
* @api public
*/
function title (data) {
if (/^ads$/i.test(data.name)) {
// this is an ad
return data.parameters.IMGURL.substring(1);
} else {
// assuming it's a regular music track
return [
inflect.titleize(data.parameters.Artist.trim()),
inflect.titleize(data.parameters.Title.trim())
].join(' - ');
}
}
@steelcowboy
Copy link

I'm trying to use your URL with mpd to stream the BONE that way, but oddly it stops after 7 seconds... any idea what's going on? Is there another stream URL I could try? How did you come across that URL?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment