Shoutcast & Icecast Stats
PHP class - Documentation

Contents

This class is extremely easy to use. It was not built for those who do not wish to get their hands dirty on doing some extra coding them selfs. You will have to design output style for your self, but class will do all the most important work for you.

Requirements
- PHP 5+
- CURL Extension with remote access OR native file_get_contents enabled with remote access
- Shoutcast (1.0 or 2.0 both supported) or Icecast (any version)
- PHP APC Cache (Optional)
How does it work ?

Class uses CURL PHP extension OR native file_get_contents to connect to your radio streams. It parses the XML returned into normal data (Yes Icecast as well). That data is then parsed into nice/compatible named array for you to write a generic output design which will work with all streams returned by class. So you might be asking your self what the hell am I writing about, here is an example of returned data by single server:


Array
(
	[listeners] => 2
	[peak] => 11
	[avg] => 20621
	[songtitle] => Klaas - Better Days Bodybangers Remix Edit
	[hits] => 873
	[status] => 1
	[path] => /ilhm.mp3
	[bitrate] => 320
	[listeners-list] => Array
		(
			[0] => Array
				(
					[HOSTNAME] => 50.7.31.146
					[USERAGENT] => WinampMPEG/5.09
					[CONNECTTIME] => 40445
					[UID] => 004F74A4
					[SERVER] => Shoutcast 320kbps - ilhm.eu
				)

			[1] => Array
				(
					[HOSTNAME] => 78.35.66.225
					[USERAGENT] => WinampMPEG/5.50
					[CONNECTTIME] => 798
					[UID] => 03972104
					[SERVER] => Shoutcast 320kbps - ilhm.eu
				)

		)

)

You just have to parse array and display it. How to do that I will cover in topics bellow.

Creating Object and Getting Data
As any other PHP Class the object call is simple:

include "radio.php";

$object = new webradio($array);

If you noticed I've added variable "$array". This variable holds details of your servers. Its obviously required so the class knows what servers to connect to. Array must be written in this format:


$array = array(

	'Shoutcast 320kbps - ilhm.eu' => array(
		'ip'    => '192.168.1.10',  // Shoutcast/Icecast server IP
		'port'  => '8000',          // Shoutcast/Icecast server PORT
		'sid'   => '1',             // Shoutcast Server ID (Stream ID) not needed for icecast
		'user'  => 'username',      // Required username for Icecast admin access
		'pw'    => '********',      // Shoutcast/Icecast admin password
		'type'  => 'shoutcast',     // Server Type, shoutcast or icecast
		'mount' => '/ilhm.ogg'      // Mount Point. Only Required for Icecast !
	)
);

Note: You do not need to repeat details if next server in array has the same details, example:


$array = array(

	'Shoutcast 320kbps - ilhm.eu' => array(
		'ip'    => '192.168.1.10',
		'port'  => '8000',
		'sid'   => '1',
		'pw'    => '********',
		'type'  => 'shoutcast',
		'mount' => '/ilhm.ogg' // Only Required for Icecast !
	),

	'Shoutcast 192kbps - ilhm.eu' => array(
		'sid'   => '2',                 // Different SID then primary server
	),
);

Now lets sum this up and get details from our servers:


$array = array(

	'Shoutcast 320kbps (MP3) - ilhm.eu' => array(
		'ip'    => '192.168.1.10',
		'port'  => '8000',
		'sid'   => '1',
		'pw'    => '********',
		'type'  => 'shoutcast',
		'mount' => '/ilhm.ogg' // Only Required for Icecast !
	),

	'Shoutcast 192kbps (MP3) - ilhm.eu' => array(
		'sid'   => '2',                 // Different SID then primary server
	),

	'Shoutcast 128kbps (MP3) - ilhm.eu' => array(
		'sid'   => '3',                 // Different SID then primary server
	),

	'Shoutcast 128kbps (AAC) - ilhm.eu' => array(
		'sid'   => '4',                 // Different SID then primary server
	),

	'Icecast 320kbps (OGG) - ilhm.eu' => array(
		'ip'    => '192.168.1.10',
		'port'  => '8005',
		'pw'    => '********',
		'user'  => 'icecastusername',  // REQUIRED for icecast
		'type'  => 'icecast',
		'mount' => '/ilhm.ogg' // REQUIRED for Icecast !
	),
);

include "radio.php";

$object = new webradio($array);
print_r($object->totals());

Output will be:
Array
(
	[listeners] => 2
	[peak] => 26
	[listen-time] => 42405
	[hits] => 1605
	[listeners-list] => Array
		(
			[0] => Array
				(
					[HOSTNAME] => 50.7.31.146
					[USERAGENT] => WinampMPEG/5.09
					[CONNECTTIME] => 42405
					[UID] => 004F74A4
					[SERVER] => Shoutcast 320kbps (MP3) - ilhm.eu
				)

			[1] => Array
				(
					[HOSTNAME] => 192.168.1.1
					[USERAGENT] => Mozilla/5.0 (Windows NT 6.2; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0
					[CONNECTTIME] => 11067
					[UID] => 34820
					[SERVER] => Icecast 320kbps (OGG) - ilhm.eu
				)

		)

	[status] => 1
)
Object Options and Functions

As we seen this class doesn't require any extra options. So you do not need to configure nothing except providing array with details to your servers. As any other class, this class has multiple functions which allow you to get your data. Here is list and description of functions:

$object->getInfo($serverID);

Will return single server details. $serverID can be empty in that case first server from array will be displayed.
Note: If you use this function, server in array must have ALL Details specified!


The Output:
Array
(
	[listeners] => 2
	[peak] => 11
	[avg] => 21566
	[songtitle] => Steve Angello - Tivoli Original Mix Edit
	[hits] => 876
	[status] => 1
	[path] => /ilhm.mp3
	[bitrate] => 320
	[listeners-list] => Array
		(
			[0] => Array
				(
					[HOSTNAME] => 50.7.31.146
					[USERAGENT] => WinampMPEG/5.09
					[CONNECTTIME] => 42910
					[UID] => 004F74A4
					[SERVER] => Shoutcast 320kbps (MP3) - ilhm.eu
				)

			[1] => Array
				(
					[HOSTNAME] => 92.225.161.228
					[USERAGENT] => WinampMPEG/5.0
					[CONNECTTIME] => 223
					[UID] => 03A0244C
					[SERVER] => Shoutcast 320kbps (MP3) - ilhm.eu
				)

		)

)

$object->totals();

This will return totals from all servers in the array.
Note: If one of servers is off-line, status will be 0! If all the servers are on-line status will be 1.


Array
(
	[listeners] => 3
	[peak] => 26
	[listen-time] => 22192
	[hits] => 1606
	[listeners-list] => Array
		(
			[0] => Array
				(
					[HOSTNAME] => 50.7.31.146
					[USERAGENT] => WinampMPEG/5.09
					[CONNECTTIME] => 43536
					[UID] => 004F74A4
					[SERVER] => Shoutcast 320kbps (MP3) - ilhm.eu
				)

			[1] => Array
				(
					[HOSTNAME] => 92.225.161.228
					[USERAGENT] => WinampMPEG/5.0
					[CONNECTTIME] => 849
					[UID] => 03A0244C
					[SERVER] => Shoutcast 320kbps (MP3) - ilhm.eu
				)

			[2] => Array
				(
					[HOSTNAME] => 192.168.1.1
					[USERAGENT] => Mozilla/5.0 (Windows NT 6.2; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0
					[CONNECTTIME] => 12198
					[UID] => 34820
					[SERVER] => Icecast 320kbps (OGG) - ilhm.eu
				)

		)

	[status] => 1
)

$object->cached(); (Works only with APC-Cache)

If your script is located on heavy loaded server and has loads of requests per second this function will cache function totals() for 60 seconds and return cached/live data. The output will be the same as $object->totals();.

What should You do with data ?

So far I've shown you all there is need to know about how to get data and use this PHP class now I'm going to explain how do you parse the data with PHP and display it. Its pretty easy if you only have some basic HTML knowledge.

Use of Javascript (JSON) highly recommended since the script can take some time to get all details from different servers !

Simple example of parsing data into HTML using single stream data:

include "radio.php"; // Include class

$object = new webradio($array); // Create Object with Servers array
$data = $object->getInfo(); // Call function to get single server details

// Avearge Listen Time in Readable format
$data['listen-time'] = floor($data['listen-time']/3600)."h ".floor(($data['listen-time'] / 60) % 60) ."m ".floor($data['listen-time'] % 60)."s";

echo "Listeners: {$data['listeners']}
Peak Listeners: {$data['peak']}
Avearge Listen Time: {$data['listen-time']}
Stream Hits: {$data['hits']}
Servers Status: {$data['status']}";

echo "Listeners:";
foreach ($data['listeners-list'] as $listener) {
	echo $listener['HOSTNAME'] . ' ';
}

Output:
Listeners: 4
Peak Listeners: 26
Avearge Listen Time: 6h 33m 3s
Stream Hits: 1610
Servers Status: 1
Listeners: 50.7.31.146 84.135.58.248 92.225.161.228 192.168.1.1

It will work the same for single server, you will just have more different data's to show. Like Current Playing Song etc...

Final Example & Last Details

I believe this documentation answered all your questions and shown you this PHP Class is really easy to use. Final Example will be simple parse of ILHM Radio's servers all shown in Simple UI. I will use HTML, jQuery, CSS3 and ShoutCast/Icecast Stats PHP class. This example refreshes data every 50 seconds.

Lets get to it. First we create style for our simple UI:

.box {
	display: inline-block;
	width: 450px;
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	border-radius: 5px;
	border: 1px solid #C8C8C8;
	background: #fff;
	margin: 5px;
	max-height: 185px;
	overflow-y: auto;
	overflow-x: hidden;
}

.box .head {
	display: block;
	font-size: 14px;
	font-weight: bold;
	height: 35px;
	line-height: 35px;
	padding-left: 15px;
	border-bottom: 1px solid #C8C8C8;
	background: #ffffff;
	background: -moz-linear-gradient(top,  #ffffff 0%, #eaeaea 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#eaeaea));
	background: -webkit-linear-gradient(top,  #ffffff 0%,#eaeaea 100%);
	background: -o-linear-gradient(top,  #ffffff 0%,#eaeaea 100%);
	background: -ms-linear-gradient(top,  #ffffff 0%,#eaeaea 100%);
	background: linear-gradient(to bottom,  #ffffff 0%,#eaeaea 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eaeaea',GradientType=0 );
	-webkit-border-top-left-radius: 5px;
	-webkit-border-top-right-radius: 5px;
	-moz-border-radius-topleft: 5px;
	-moz-border-radius-topright: 5px;
	border-top-left-radius: 5px;
	border-top-right-radius: 5px;
}

.box .box-content {
	font-size: 12px;
	display: block;
	width: 100%;
	font-family: Arial, sans-serif;
	line-height: 120%;
}

.box .listener {
	display: block;
	width: 100%;
	clear: both;
	height: 22px;
	cursor: pointer;
}

.box .listener:hover {
	background: #f0f0f0;
}

.box .listener .col {
	display: block;
	width: 33%;
	float: left;
	height: 22px;
	line-height: 22px;
	text-align: center;
	overflow: hidden;
}

.box .radioDetails {
	float: left;
	display: block;
	width: 285px;
	padding: 10px;
	line-height: 160%;
}

.box .radioLogo {
	float: left;
	width: 125px;
	border-right: 1px solid #C8C8C8;
}

The Javascript (This one works INLINE meaning u can put it anywhere in the HTML)


<script type="text/javascript">
			$(document).ready(function() {
					readInfo();
					window.setInterval("readInfo()", 50000 ); // Repeats function every 50 seconds
			});

			function readInfo() {

				$.getJSON("/projects/radio-class/test.php", function (data) {

						$("#total").html(data.listeners);
						$("#peaklisten").html(data.peak);
						$("#hits").html(data.hits);
						$("#avg").html(data['listen-time']);

						$("#listeners").empty();

						if ($.isArray(data["listeners-list"])) {

							$.each(data["listeners-list"], function(val, listener) {

									$("#listeners").append('<div class="listener"> \
										<div class="col">' + listener.HOSTNAME + '</div> \
										<div class="col">' + listener.USERAGENT + '</div> \
										<div class="col">' + listener.CONNECTTIME + '</div> \
										</div>');
							});
						}

				});

			}
</script>

And of course the PHP file that parses all the data into JSON array (Makes it good for our simple jQuery script)


<?php
	include "radio.php";

	$radio = array(

		'Shoutcast 320kbps (MP3) - ilhm.eu' => array(
			'ip'    => '192.168.1.10',
			'port'  => '8000',
			'sid'   => '1',
			'pw'    => '********',
			'type'  => 'shoutcast',
			'mount' => 'ilhm.ogg' // Only Required for Icecast !
		),

		'Shoutcast 192kbps (MP3) - ilhm.eu' => array(
			'sid'   => '2',                 // Different SID then primary server
		),

		'Shoutcast 128kbps (MP3) - ilhm.eu' => array(
			'sid'   => '3',                 // Different SID then primary server
		),

		'Shoutcast 128kbps (AAC) - ilhm.eu' => array(
			'sid'   => '4',                 // Different SID then primary server
		),

		'Icecast 320kbps (OGG) - ilhm.eu' => array(
			'ip'    => '192.168.1.10',
			'port'  => '8005',
			'user'  => 'username',
			'pw'    => '********',
			'type'  => 'icecast',
			'mount' => 'ilhm.ogg' // Only Required for Icecast !
		),
	);

	$object = new webradio($radio); // Create Object
	if ($_GET['servid'] == "") { // Check if servid is specified, if not display info from all servers
		$data = $object->totals();
	} else { // If defined, display specified server only
		$data = $object->getInfo($_GET['servid']);
	}

	if (is_array($data['listeners-list'])) { // Make listener connection time in readable format
		foreach($data['listeners-list'] as $key => $l) {
			$data['listeners-list'][$key]['CONNECTTIME'] = floor($l['CONNECTTIME']/3600)."h ".floor(($l['CONNECTTIME'] / 60) % 60) ."m ".floor($l['CONNECTTIME'] % 60)."s";
		}
	}

	// Avearge Listen Time in Readable format
	$data['listen-time'] = floor($data['listen-time']/3600)."h ".floor(($data['listen-time'] / 60) % 60) ."m ".floor($data['listen-time'] % 60)."s";

	echo json_encode($data); // Finnaly display encoded data.
?>

AND finally the HTML output:


<div class="box">
	<div class="head"><i class="icon-play-circle"></i> &nbsp; ILHM Radio - All Servers</div>
		<div class="box-content">
			<div class="radioLogo">
				<img src="/projects/radio-class/radio-logo.jpg">
			</div>
		<div class="radioDetails">
				<b>Listeners:</b> <span id="total">0</span> <br />
				<b>Listener Peak:</b> <span id="peaklisten">0</span> <br />
				<b>Total Stream Hits:</b> <span id="hits">0</span> <br />
				<b>Avearge Listen Time:</b> <span id="avg">0m</span>
			</div>
			<div class="clearfix" style="border-bottom: 1px solid #C8C8C8;"></div>
			<div class="listener">
				<div class="col">Hostname</div>
				<div class="col">Useragent (Player)</div>
				<div class="col">Listen Time</div>
			</div>
		<div id="listeners"></div>
	</div>
</div>

Finished Product:

  ILHM Radio - All Servers
Listeners: 0
Listener Peak: 0
Total Stream Hits: 0
Average Listen Time: 0m
Hostname
Useragent (Player)
Listen Time