--- /dev/null
+iceplex
+
+Copyright (c) 2003 Ivan Kohler
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+ivan-iceplex@420.am
+
+iceplex is a system for multiplexing on-demand broadcasts to multiple
+backend icecast servers.
+
+To use:
+
+Database configuration:
+
+ - Create the "iceplex_servers" table in your database
+ (see create-mysql.sql or create-Pg.sql)
+ - Populate the "iceplex_servers" table with your icecast server names.
+
+On the central multiplexing server:
+
+ - Copy the example iceplex.conf to /etc/iceplex.conf and modify the settings
+ as appropriate:
+ - Database location/user/pass
+ - Path to mp3 file storage on the icecast servers.
+ - Icecast Port number
+ - Run iceplexd and configure your init scripts to start it upon boot.
+ - Create an "iceplex" user.
+ - Run "ssh-keygen -t dsa" as the "iceplex" user to genarate SSH keys.
+ Use a blank passphrase. (Press return when prompted for a passphrase)
+ - Install Net::SSH from CPAN or <http://search.cpan.org/author/IVAN/Net-SSH/>
+ - Install DBI from CPAN or <http://search.cpan.org/author/TIMB/DBI/>
+ - Install the DBD for your database
+ - MySQL: DBD::mysql from CPAN or
+ <http://search.cpan.org/author/JWIED/DBD-mysql/>
+ - PostgreSQL: DBD::Pg from CPAN or
+ <http://search.cpan.org/author/DWHEELER/DBD-Pg/>
+ - Install plex.pls in /cgi-bin/ on the central multiplexing server or main
+ webserver. This file can be installed as or linked to as "plex.m3u" if
+ desired.
+
+On each icecast server:
+
+ - Create an "iceplex" user.
+ - Copy "/home/iceplex/.ssh/id_dsa.pub" from the central multiplexing server
+ to "/home/iceplex/.ssh/authorized_keys".
+ - Verify that the
+ - Install libshout C library 1.0.9 and Shout perl interface:
+ <http://developer.icecast.org/libshout/>
+ - Install yashout from this archive in /usr/local/bin
+
+On end-user webpages:
+
+ - Link to:
+ <http://multi.plexing.server/cgi-bin/plex.pls?customer=XXXXXX;user=YYYY>
+
+Optional, improves stream start latency:
+
+ - Install fsh <http://www.lysator.liu.se/fsh/> on the central multiplexing
+ server and each icecast server.
+ - Uncomment
+ $Net::SSH:ssh = 'fsh';
+ in /etc/iceplex.conf
+
--- /dev/null
+- mp3 file storage should be in hashed directories for scalability
--- /dev/null
+create table iceplex_servers (
+ servernum serial primary key,
+ servername varchar(255)
+ listeners int,
+ status varchar(255),
+);
+
--- /dev/null
+create table iceplex_servers (
+ servernum int primary key auto_increment,
+ servername varchar(255),
+ listeners int,
+ status varchar(255),
+);
+
--- /dev/null
+
+Playlist file extensions and MIME types:
+http://www.dnalounge.com/audio/faq.html#configuration
+
+.pls file looks like:
+[playlist]
+NumberOfEntries=1
+File1=http://server:port/mountpoint
+
+.m3u file is even simpler:
+http://server:port/mountpoint
+
--- /dev/null
+# iceplex configuration file - /etc/iceplex.conf
+
+###
+# normal configuration
+###
+
+#database connection info
+$dsn = 'DBI:mysql:imedia';
+$user = 'imedia';
+$pass = 'imedia';
+
+#path to mp3 files on icecast servers
+$mp3path = '/home/ivan/plexmp3';
+
+#icecast port number
+$port = 8000;
+
+#(optional) file number override query
+# the first ? is replaced with the customer and second ? with the user
+#
+#$override_query = "SELECT filenumber FROM overrides ".
+# "WHERE customer = ? AND user = ?";
+
+#normal file number query
+# (used if the override query is not specified or does not return a value)
+# the first ? is replaced with the customer and second ? with the user
+#
+#$fileno_query = "SELECT MAX(filenumber) FROM files ".
+# "WHERE customer = ? AND user = ?";
+
+#(if the normal query is not specified, file number defaults to '000')
+
+###
+# advanced options
+###
+
+#install fsh on both ends and uncomment this for better stream start latency
+#$Net::SSH::ssh = 'fsh';
+
+#mime types
+%extension2type = (
+ 'pls' => 'audio/x-scpls',
+ 'm3u' => 'audio/x-mpegurl',
+ #'m3u' => 'audio/mpegurl',
+);
+
+
--- /dev/null
+#!/usr/bin/perl
--- /dev/null
+#!/usr/bin/perl -w
+#
+# iceplex
+#
+# Copyright (c) 2003 Ivan Kohler
+# All rights reserved.
+# This program is free software; you can redistribute it and/or modify it under
+# the same terms as Perl itself.
+
+use strict;
+use subs qw(pick_server);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use Digest::MD5;
+use Net::SSH qw(ssh);
+
+# pull in configuration
+use vars qw($dsn $user $pass $mp3path $port);
+use vars qw($override_query $fileno_query);
+use vars qw(%extension2type);
+require "/etc/iceplex.conf";
+
+#detect .pls or .m3u filetype
+$0 =~ /\.(pls|m3u)$/i or die "must be named with .pls or .m3u extension";
+my $extension = lc($1);
+
+#connect to database
+my $dbh = DBI->connect($dsn, $user, $pass) or die $DBI::errstr;
+
+#pick a server
+my $server = pick_server();
+
+#get customer & user from client browser
+my $cgi = new CGI;
+$cgi->param('customer') =~ /^(\d{1,10})$/ or die 'illegal customer numer';
+my $customer = sprintf("%6d", $1); #!! how many digits in customer #?
+$cgi->param('user') =~ /^(\d{1,10})$/ or die 'illegal user numer';
+my $user = sprintf("%4d", $1); #!! how many digits in user #?
+
+#get file number
+my $fileno = '';
+if ( $override_query ) {
+ my $sth = $dbh->prepare( $override_query ) or die $dbh->errstr;
+ $sth->execute($customer, $user) or die $sth->errstr;
+ my $row = $sth->fetchrow_arrayref;
+ $fileno = $row->[0] if $row;
+}
+if ( !length($fileno) && $fileno_query ) {
+ my $sth = $dbh->prepare( $fileno_query ) or die $dbh->errstr;
+ $sth->execute($customer, $user) or die $sth->errstr;
+ my $row = $sth->fetchrow_arrayref;
+ die "No files for user $user of customer $customer" unless $row;
+ $fileno = $row->[0];
+}
+$fileno = '000' unless length($fileno); #default
+
+#genarate filename
+my $filename = "$mp3path/$customer-$user-$fileno.mp3";
+
+#disconnect from database
+$dbh->disconnect;
+
+#generate a mountpoint
+my $mountpoint = md5_hex($cgi->remote_host. $$. time. int(rand(4294967296)));
+
+#signal encoder to start streaming to mountpoint & wait for confirmation
+ssh($server, 'yashout', $filename, $mountpoint );
+
+#send file back to client browser
+
+print $cgi->header( -type => $extension2type{$extension} );
+print "[playlist]\nNumberOfEntries=1\n" if $extension eq 'pls';
+print "http://$server:$port/$mountpoint\n";
+
+###
+# subroutiens
+###
+
+sub pick_server {
+ my $sth = $dbh->prepare(
+ "SELECT servername FROM iceplex_servers ".
+ "WHERE status = 'online' ".
+ "ORDER BY listeners ASC LIMIT 1"
+ ) or die $dbh->errstr;
+ $sth->execute() or die $sth->errstr;
+ my $row = $sth->fetchrow_arrayref;
+ die "No servers online!" unless $row;
+ $row->[0];
+}
+
--- /dev/null
+#!/usr/bin/perl
+#
+# yashout
+# Usage: yashout filename mountpoint
+#
+# Copyright (c) 2003 Ivan Kohler
+# All rights reserved.
+# This program is free software; you can redistribute it and/or modify it under
+# the same terms as Perl itself.
+
+use Shout;