#!/usr/bin/perl # # Music.pl version 0.6 # # Sam Heller (sheller@marlboro.edu) # # 10/28/03 # # # # This script works in conjunction with # # a MySQL Database created by Register.pl # # To query the mp3's available on your hard # # drive, and present a web based interface # # to stream them to any computer with an mp3 # # player capable of receiving streams. # # # # Problems With This Version : # # - Full ICY protocol is not implemented # # - Only capable of streaming playlists # # - Not able to package metadata with streams # # - Port Numbers are not randomly generated # # - Probably plenty more I don't remember # # # # This is not meant to be a functional version # # at this point, but it's getting there. # #==============================================# #===========================================# # Socket For Streaming # # DBD::mysql For interfacing w/ mysql db # # CGI For generating web frontend # #===========================================# use Socket; use DBD::mysql; use CGI; #================================# # See if we've got a stream to # # serve up, otherwise, go to the # # web frontend # #================================# $Stream = $page->param("Stream"); if ($Stream) { &Stream ; } else { &Web ; } sub Web { #============================================# # Open up the Connection to the MySQL DB and # # create the web page object. Also grab any # # input that may be coming from the webpage # #============================================# $dbh = DBI->connect("DBI:mysql:music","root","") or die "Can't connect to MySQL DB : $!"; $page = new CGI; $Band = $page->param("BandRequest"); $BandID = $page->param("BandID"); $AlbumID = $page->param("AlbumID"); $New = $page->param("New"); $BandName = $page->param("BandName"); $AlbumName = $page->param("AlbumName"); #========================================# # If we are getting a fresh query, grab # # the Band names and ID's from the MySQL # # DB and push them into the arrays # # @BandName and @BandID. # #========================================# if ($New) { $sth = $dbh->prepare("SELECT * FROM Band"); $sth->execute(); my @BandName; my @BandID; $x = 0; while ($ref = $sth->fetchrow_hashref()) { push (@BandName, $ref->{'BandName'}); push (@BandID, $ref->{'BandID'}); } #=============================================# # Print out the page headers and info, then # # loop through all the entries and list the # # Bands with hyperlinks to query this script # # again. We need to autoincrement $x so that # # The BandID can be synced with the Band Name # #=============================================# print $page->header( "text/html" ), $page->start_html( "Band Listings" ), $page->h1( "Band Listings" ), $page->p( "These are the Bands currently available for streaming" ); foreach (@BandName) { print $page->br("$_"); $x++; } print $page->end_html; $sth->finish; $dbh->disconnect; } #=============================================# # If the script is passed a BandID, troll the # # MySQL DB, get all the albums from that band # # that are available, and stick that and the # # corresponding album ID into @AlbumName and # # AlbumID. # #=============================================# elsif ($BandID) { $sth = $dbh->prepare("SELECT * FROM Album WHERE BandID=$BandID"); $sth->execute(); my @AlbumName; my @AlbumID; $x = 0; print $page->header("text/html"), $page->start_html("Album Listing"), $page->h1("Album's Available"); while ($ref = $sth->fetchrow_hashref()) { push (@AlbumName, $ref->{'AlbumName'}); push (@AlbumID, $ref->{'AlbumID'}); } foreach (@AlbumName) { print $page->br("$_"); $x++; } print $page->end_html; $sth->finish; $dbh->disconnect; } elsif ($AlbumID) { $sth = $dbh->prepare("SELECT * FROM Song WHERE AlbumID=$AlbumID"); $sth->execute(); my @SongName; my @SongPath; my @TrackNumber; my @TrackID; $x = 0; while ($ref = $sth->fetchrow_hashref()) { push (@SongName, $ref->{'SongName'}; push (@SongPath, $ref->{'SongPath'}; push (@TrackNumber, $ref->{'TrackNumber'}; push (@TrackID, $ref->{'TrackID'}; } print $page->header( "text/html" ), $page->start_html( "Track Listing" ), $page->h2( "Track Listing" ); foreach (@SongName) { s/.mp3//; print $page->br("Track $TrackNumber[$x] :$_ ID=$TrackID[$x]"); $x++; } print $page->end_html; $sth->finish; $dbh->disconnect; } else { print $page->header( "text\html" ), $page->start_html( "Error" ), $page->h2( "Your Input was Invalid" ), $page->end_html; } } sub Stream { #======================================# # Open up the connection to the server # # and declare our variables # #======================================# $dbh = DBI->connect("DBI:mysql:music","root","") or die "Couldn't Open DB : $!" ; my @SongName; my @SongPath; my @TrackPath; #======================# # Configure the socket # #======================# $port = 8080; $domain = PF_INET; $type = SOCK_STREAM; $proto = getprotobyname('tcp') ; $sockaddr = sockaddr_in($port, INADDR_ANY); #==========================# # Open and Bind the Socket # #==========================# socket (CLIENT, $domain, $type, $proto) or die "socket : $!\n"; bind(CLIENT, $sockaddr) or die "bind : $!\n"; #==================================================# # Grab the Album info from the MySQL DB using # # AlbumID, put together the full path of the song, # # and push it onto the array @Playlist. # #==================================================# $sth = $dbh->prepare("SELECT * FROM Song WHERE AlbumID = $AlbumID"); $sth ->execute(); while ($ref = $sth->fetchrow_hashref()) { $buffer = join '', $ref->{'SongPath'} , $ref->{'SongName'}; push (@Playlist, $buffer); } $sth->finish; $dbh->disconnect; #===============================# # Open the socket and assign it # # to fileandle HANDLER. # #===============================# listen(CLIENT, SOMAXCONN) or die "listen : $!\n"; $sockaddr = accept(HANDLER, CLIENT) or die "accept : $!\n"; ($port, $ip_addr) = sockaddr_in($sockaddr) or die "new $!\n"; #===================================================# # Once the client has connected, send them the # # initial ICY dialouge, then open up the playlist # # and start serving up the music. This is in no way # # way complete at this point. I still need to # # implement the full ICY protocol instead of sorta # # half assing it, and I'd like to be able to send # # the song's metadata along with the file. # #===================================================# print HANDLER "HTTP/1.0 200 OK\n\n"; foreach ( @Playlist ) { open MP3, $_ or die "Couldn't Open $_ for reading : $! \n"; while (read MP3, $buffer, 8192) { print HANDLER $buffer; } close MP3; } close CLIENT; }