diff --git a/application/controllers/ApiController.php b/application/controllers/ApiController.php
index b4dd0d3a2..f7ff37eb1 100644
--- a/application/controllers/ApiController.php
+++ b/application/controllers/ApiController.php
@@ -109,6 +109,16 @@ class ApiController extends Zend_Controller_Action
         $this->_helper->viewRenderer->setNoRender(true);
 
         $result = Schedule::GetPlayOrderRange(0, 1);
+
+        $date = new Application_Model_DateHelper;
+        $timeNow = $date->getDate();
+        $result = array("env"=>APPLICATION_ENV,
+            "schedulerTime"=>gmdate("Y-m-d H:i:s"),
+            "currentShow"=>Show_DAL::GetCurrentShow($timeNow),
+            "nextShow"=>Show_DAL::GetNextShows($timeNow, 5),
+            "timezone"=> date("T"),
+            "timezoneOffset"=> date("Z"));
+            
         //echo json_encode($result);
         header("Content-type: text/javascript");
         echo $_GET['callback'].'('.json_encode($result).')';
diff --git a/application/models/Schedule.php b/application/models/Schedule.php
index 47faa7ddc..21419c4f0 100644
--- a/application/models/Schedule.php
+++ b/application/models/Schedule.php
@@ -24,41 +24,6 @@ class ScheduleGroup {
         return $result != "0";
     }
 
-    /**
-     * Convert a date to an ID by stripping out all characters
-     * and padding with zeros.
-     *
-     * @param string $p_dateStr
-     */
-    public static function dateToId($p_dateStr) {
-        $p_dateStr = str_replace(":", "", $p_dateStr);
-        $p_dateStr = str_replace(" ", "", $p_dateStr);
-        $p_dateStr = str_replace(".", "", $p_dateStr);
-        $p_dateStr = str_replace("-", "", $p_dateStr);
-        $p_dateStr = substr($p_dateStr, 0, 17);
-        $p_dateStr = str_pad($p_dateStr, 17, "0");
-        return $p_dateStr;
-    }
-
-    /**
-     * Add the two times together, return the result.
-     *
-     * @param string $p_baseTime
-     *  Specified as YYYY-MM-DD HH:MM:SS
-     *
-     * @param string $p_addTime
-     *  Specified as HH:MM:SS.nnnnnn
-     *
-     * @return string
-     *    The end time, to the nearest second.
-     */
-    //  protected function calculateEndTime($p_startTime, $p_trackTime) {
-    //    $p_trackTime = substr($p_startTime, 0, );
-    //    $start = new DateTime();
-    //    $interval = new DateInterval()
-    //
-    //  }
-
     /**
      * Add a music clip or playlist to the schedule.
      *
@@ -77,6 +42,7 @@ class ScheduleGroup {
      */
     public function add($show_instance, $p_datetime, $p_audioFileId = null, $p_playlistId = null, $p_options = null) {
         global $CC_CONFIG, $CC_DBC;
+
         if (!is_null($p_audioFileId)) {
             // Schedule a single audio track
 
@@ -92,26 +58,24 @@ class ScheduleGroup {
             if (empty($length)) {
                 return new PEAR_Error("Length is empty.");
             }
-            if (!Schedule::isScheduleEmptyInRange($p_datetime, $length)) {
-                return new PEAR_Error("Schedule conflict.", 555);
-            }
-
+           
             // Insert into the table
             $this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
-            $id = $this->dateToId($p_datetime);
+           
             $sql = "INSERT INTO ".$CC_CONFIG["scheduleTable"]
-            ." (playlist_id, starts, ends, clip_length, group_id, file_id)"
-            ." VALUES (0, TIMESTAMP '$p_datetime', "
+            ." (instance_id, starts, ends, clip_length, group_id, file_id, cue_out)"
+            ." VALUES ($show_instance, TIMESTAMP '$p_datetime', "
             ." (TIMESTAMP '$p_datetime' + INTERVAL '$length'),"
             ." '$length',"
-            ." {$this->groupId}, $p_audioFileId)";
+            ." {$this->groupId}, $p_audioFileId, '$length')";
             $result = $CC_DBC->query($sql);
             if (PEAR::isError($result)) {
                 //var_dump($sql);
                 return $result;
             }
 
-        } elseif (!is_null($p_playlistId)){
+        } 
+        elseif (!is_null($p_playlistId)){
             // Schedule a whole playlist
 
             // Load existing playlist
@@ -129,7 +93,6 @@ class ScheduleGroup {
 
             // Insert all items into the schedule
             $this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
-            $id = $this->dateToId($p_datetime);
             $itemStartTime = $p_datetime;
 
             $plItems = $playlist->getContents();
@@ -150,14 +113,13 @@ class ScheduleGroup {
                     return $result;
                 }
                 $itemStartTime = $CC_DBC->getOne("SELECT TIMESTAMP '$itemStartTime' + INTERVAL '$trackLength'");
-                $id = $this->dateToId($itemStartTime);
             }
         }
         RabbitMq::PushSchedule();
         return $this->groupId;
     }
 
-    public function addAfter($show_instance, $p_groupId, $p_audioFileId) {
+    public function addFileAfter($show_instance, $p_groupId, $p_audioFileId) {
         global $CC_CONFIG, $CC_DBC;
         // Get the end time for the given entry
         $sql = "SELECT MAX(ends) FROM ".$CC_CONFIG["scheduleTable"]
@@ -471,7 +433,7 @@ class Schedule {
             "current"=>Schedule::GetScheduledItemData($timeNow, 0),
             "next"=>Schedule::GetScheduledItemData($timeNow, 1, $next, "48 hours"),
             "currentShow"=>Show_DAL::GetCurrentShow($timeNow),
-            "nextShow"=>Show_DAL::GetNextShow($timeNow),
+            "nextShow"=>Show_DAL::GetNextShows($timeNow, 1),
             "timezone"=> date("T"),
             "timezoneOffset"=> date("Z"),
             "apiKey"=>$CC_CONFIG['apiKey'][0]);
diff --git a/application/models/Shows.php b/application/models/Shows.php
index ee7a9873c..f0a7a20bc 100644
--- a/application/models/Shows.php
+++ b/application/models/Shows.php
@@ -678,7 +678,7 @@ class ShowInstance {
 	}
 
 	public function addPlaylistToShow($plId)
-	{
+    {
 		$sched = new ScheduleGroup();
 		$lastGroupId = $this->getLastGroupId();
 
@@ -692,12 +692,26 @@ class ShowInstance {
 		RabbitMq::PushSchedule();
 	}
 
-	public function scheduleShow($plIds)
-	{
+    public function addFileToShow($file_id) 
+    {
+        $sched = new ScheduleGroup();
+		$lastGroupId = $this->getLastGroupId();
+        
+		if(is_null($lastGroupId)) {
+
+			$groupId = $sched->add($this->_instanceId, $this->getShowStart(), $file_id);		
+		}
+		else {
+			$groupId = $sched->addFileAfter($this->_instanceId, $lastGroupId, $file_id);
+		}
+        RabbitMq::PushSchedule();
+    }
+
+	public function scheduleShow($plIds) {
+
 		foreach($plIds as $plId) {
 			$this->addPlaylistToShow($plId);
 		}
-		RabbitMq::PushSchedule();
 	}
 
 	public function removeGroupFromShow($group_id)
@@ -744,6 +758,17 @@ class ShowInstance {
             ->findPK($this->_instanceId);
         $showInstance->setDbRecordedFile($file_id)
             ->save();
+
+        $rebroadcasts =  CcShowInstancesQuery::create()
+            ->filterByDbOriginalShow($this->_instanceId)
+            ->find();
+
+        foreach ($rebroadcasts as $rebroadcast) {
+
+            $rebroad = new ShowInstance($rebroadcast->getDbId());
+            $rebroad->addFileToShow($file_id);
+            RabbitMq::PushSchedule();
+        }
     }
 
     public function getTimeScheduled()
@@ -864,7 +889,7 @@ class Show_DAL {
         return $rows;
     }
 
-    public static function GetNextShow($timeNow)
+    public static function GetNextShows($timeNow, $limit)
     {
         global $CC_CONFIG, $CC_DBC;
 
@@ -874,7 +899,7 @@ class Show_DAL {
 		." AND si.starts >= TIMESTAMP '$timeNow'"
 		." AND si.starts < TIMESTAMP '$timeNow' + INTERVAL '48 hours'"
         ." ORDER BY si.starts"
-        ." LIMIT 1";
+        ." LIMIT $limit";
 
         $rows = $CC_DBC->GetAll($sql);
         return $rows;
diff --git a/application/models/airtime/map/CcScheduleTableMap.php b/application/models/airtime/map/CcScheduleTableMap.php
index 3f2502f1c..92afaab0c 100644
--- a/application/models/airtime/map/CcScheduleTableMap.php
+++ b/application/models/airtime/map/CcScheduleTableMap.php
@@ -39,7 +39,7 @@ class CcScheduleTableMap extends TableMap {
 		$this->setPrimaryKeyMethodInfo('cc_schedule_id_seq');
 		// columns
 		$this->addPrimaryKey('ID', 'DbId', 'INTEGER', true, null, null);
-		$this->addColumn('PLAYLIST_ID', 'DbPlaylistId', 'INTEGER', true, null, null);
+		$this->addColumn('PLAYLIST_ID', 'DbPlaylistId', 'INTEGER', false, null, null);
 		$this->addColumn('STARTS', 'DbStarts', 'TIMESTAMP', true, null, null);
 		$this->addColumn('ENDS', 'DbEnds', 'TIMESTAMP', true, null, null);
 		$this->addColumn('GROUP_ID', 'DbGroupId', 'INTEGER', false, null, null);
diff --git a/build/schema.xml b/build/schema.xml
index 36941da37..f00ad14fb 100644
--- a/build/schema.xml
+++ b/build/schema.xml
@@ -234,7 +234,7 @@
   </table>
   <table name="cc_schedule" phpName="CcSchedule">
     <column name="id" phpName="DbId" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
-    <column name="playlist_id" phpName="DbPlaylistId" type="INTEGER" required="true"/>
+    <column name="playlist_id" phpName="DbPlaylistId" type="INTEGER" required="false"/>
     <column name="starts" phpName="DbStarts" type="TIMESTAMP" required="true"/>
     <column name="ends" phpName="DbEnds" type="TIMESTAMP" required="true"/>
     <column name="group_id" phpName="DbGroupId" type="INTEGER" required="false"/>
diff --git a/build/sql/schema.sql b/build/sql/schema.sql
index ee2f9b109..71ff970ef 100644
--- a/build/sql/schema.sql
+++ b/build/sql/schema.sql
@@ -345,7 +345,7 @@ DROP TABLE "cc_schedule" CASCADE;
 CREATE TABLE "cc_schedule"
 (
 	"id" serial  NOT NULL,
-	"playlist_id" INTEGER  NOT NULL,
+	"playlist_id" INTEGER,
 	"starts" TIMESTAMP  NOT NULL,
 	"ends" TIMESTAMP  NOT NULL,
 	"group_id" INTEGER,
diff --git a/install/airtime-install.php b/install/airtime-install.php
index 55d5ba068..ffcdea662 100644
--- a/install/airtime-install.php
+++ b/install/airtime-install.php
@@ -55,6 +55,9 @@ AirtimeInstall::SetUpPythonEggs();
 echo PHP_EOL."*** Pypo Installation ***".PHP_EOL;
 system("python ".__DIR__."/../pypo/install/pypo-install.py");
 
+echo PHP_EOL."*** Recorder Installation ***".PHP_EOL;
+system("python ".__DIR__."/../python_apps/show-recorder/install/recorder-install.py");
+
 
 echo "******************************* Install Complete *******************************".PHP_EOL;
 
diff --git a/install/airtime-uninstall.php b/install/airtime-uninstall.php
index 181006efd..d175856d5 100644
--- a/install/airtime-uninstall.php
+++ b/install/airtime-uninstall.php
@@ -83,5 +83,8 @@ AirtimeInstall::DeleteFilesRecursive($CC_CONFIG['storageDir']);
 
 $command = "python ".__DIR__."/../pypo/install/pypo-uninstall.py";
 system($command);
+
+$command = "python ".__DIR__."/../python_apps/show-recorder/install/recorder-uninstall.py";
+system($command);
 echo "****************************** Uninstall Complete ******************************".PHP_EOL;
 
diff --git a/plugins/jquery.showinfo.js b/plugins/jquery.showinfo.js
index da5be1af8..c31381a10 100644
--- a/plugins/jquery.showinfo.js
+++ b/plugins/jquery.showinfo.js
@@ -2,25 +2,64 @@
  $.fn.airtimeShowSchedule = function(options) {
 
     var defaults = {
-        updatePeriod: 5, //seconds
+        updatePeriod: 20, //seconds
+        sourceDomain: "http://localhost/", //where to get show status from
     };
     var options = $.extend(defaults, options);
 
     return this.each(function() {
         var obj = $(this);
+        var sd;
 
-        obj.append("<h3>On air today</h3>");
-        obj.append(
-            "<table width='100%' border='0' cellspacing='0' cellpadding='0' class='widget widget no-playing-list small'>"+
-            "<tbody><tr>" +
-            "<td class='time'>13:15 - 13:30</td>" +
-            "<td><a href='#'>Program name</a> <a href='#' class='listen'>Listen</a></td>" +
-            "</tr>"+
-            "<tr>"+
-            "<td class='time'>13:15 - 13:30</td>"+
-            "<td><a href='#'>Lorem ipsum dolor</a></td>"+
-            "</tr>"+
-            "</tbody></table>");
+        getServerData();
+
+        function updateWidget(){
+            var currentShow = sd.getCurrentShow();
+            var nextShows = sd.getNextShows();
+
+            var currentShowName = "";
+            var nextShowName = ""
+
+            if (currentShow.length > 0){
+                currentShowName = currentShow[0].getName();
+            }
+            
+            if (nextShows.length > 0){
+                nextShowName = nextShows[0].getName();
+            }
+
+            tableString = "";
+            tableString += "<h3>On air today</h3>";
+            tableString += "<table width='100%' border='0' cellspacing='0' cellpadding='0' class='widget widget no-playing-list small'>"+
+                "<tbody>";
+            
+            var shows=currentShow.concat(nextShows);
+            
+            obj.empty();
+            for (var i=0; i<shows.length; i++){
+                tableString +=
+                "<tr>" +
+                "<td class='time'>"+shows[i].getRange()+"</td>" +
+                "<td><a href='#'>"+shows[i].getName()+"</a> <a href='#' class='listen'>Listen</a></td>" +
+                "</tr>";
+            }
+
+            tableString += "</tbody></table>";
+            
+            obj.append(tableString);
+        }
+
+        function processData(data){
+            sd = new ScheduleData(data);
+            updateWidget();
+        }
+
+        function getServerData(){
+            $.ajax({ url: options.sourceDomain + "api/live-info/", dataType:"jsonp", success:function(data){
+                        processData(data);
+                  }, error:function(jqXHR, textStatus, errorThrown){}});
+            setTimeout(getServerData, defaults.updatePeriod*1000);
+        }
     });
  };
 })(jQuery);
@@ -42,24 +81,42 @@
         getServerData();
 
         function updateWidget(){
-            var currentShow = sd.getCurrentShowName();
-            var timeRemaining = sd.getCurrentShowTimeRemaining();
-            var timeElapsed = sd.getCurrentShowTimeElapsed();
-            var showStatus = sd.getCurrentShowStatus();
+            var currentShow = sd.getCurrentShow();
+            var nextShows = sd.getNextShows();
 
-            var nextShow = sd.getNextShowName();
-            var nextShowRange = sd.getNextShowRange();
+            var showStatus = "Offline";
+            var currentShowName = "";
+            var timeElapsed = "";
+            var timeRemaining = "";
+
+            var nextShowName = "";
+            var nextShowRange = "";
+
+            if (currentShow.length > 0){
+                showStatus = "On Air Now";
+                currentShowName = currentShow[0].getName();
+
+                timeElapsed = sd.getShowTimeElapsed(currentShow[0]);
+                timeRemaining = sd.getShowTimeRemaining(currentShow[0]);
+            }
+
+            if (nextShows.length > 0){
+                nextShowName = nextShows[0].getName();
+                nextShowRange = nextShows[0].getRange();
+            }
 
             obj.empty();
             obj.append("<a id='listenWadrLive'><span>Listen WADR Live</span></a>");
             obj.append("<h4>"+showStatus+" &gt;&gt;</h4>");
             obj.append("<ul class='widget no-playing-bar'>" +
-                "<li class='current'>"+currentShow+ "<span id='time-elapsed' class='time-elapsed'>"+timeElapsed+"</span>" +
-                "<span id='time-remaining' class='time-remaining'>"+timeRemaining+"</span></li>" +
-                "<li class='next'>"+nextShow+"<span>"+nextShowRange+"</span></li>" +
+                "<li class='current'>Current: "+currentShowName+
+                "<span id='time-elapsed' class='time-elapsed'>"+timeElapsed+"</span>" +
+                "<span id='time-remaining' class='time-remaining'>"+timeRemaining+"</span>"+
+                "</li>" +
+                "<li class='next'>Next: "+nextShowName+"<span>"+nextShowRange+"</span></li>" +
                 "</ul>");
 
-            //refresh the UI
+            //refresh the UI to update the elapsed/remaining time
             setTimeout(updateWidget, 1000);
         }
 
@@ -78,12 +135,23 @@
  };
 })(jQuery);
 
-/* The rest of this file is the ScheduleData class */
+/* ScheduleData class BEGIN */
 function ScheduleData(data){
     this.data = data;
     this.estimatedSchedulePosixTime;
 
-    this.schedulePosixTime = this.convertDateToPosixTime(data.schedulerTime);
+    this.currentShow = new Array();
+    for (var i=0; i< data.currentShow.length; i++){
+        this.currentShow[i] = new Show(data.currentShow[i]);
+    }
+
+    this.nextShows = new Array();
+    for (var i=0; i< data.nextShow.length; i++){
+        this.nextShows[i] = new Show(data.nextShow[i]);
+    }
+    
+
+    this.schedulePosixTime = convertDateToPosixTime(data.schedulerTime);
     this.schedulePosixTime += parseInt(data.timezoneOffset)*1000;
     var date = new Date();
     this.localRemoteTimeOffset = date.getTime() - this.schedulePosixTime;
@@ -95,72 +163,57 @@ ScheduleData.prototype.secondsTimer = function(){
     this.estimatedSchedulePosixTime = date.getTime() - this.localRemoteTimeOffset;
 }
 
-ScheduleData.prototype.getCurrentShowName = function() {
-    var currentShow = this.data.currentShow;
-    if (currentShow.length > 0){
-        return "Current: " + currentShow[0].name;
-    } else {
-        return "";
-    }
-};
+ScheduleData.prototype.getCurrentShow = function(){
+    return this.currentShow;
+}
 
-ScheduleData.prototype.getCurrentShowStatus = function() {
-    var currentShow = this.data.currentShow;
-    if (currentShow.length > 0){
-        return "On Air Now";
-    } else {
-        return "Offline";
-    }
-};
+ScheduleData.prototype.getNextShows = function() {
+    return this.nextShows;
+}
 
-ScheduleData.prototype.getNextShowName = function() {
-    var nextShow = this.data.nextShow;
-    if (nextShow.length > 0){
-        return "Next: " + nextShow[0].name;
-    } else {
-        return "";
-    }
-};
-
-ScheduleData.prototype.getNextShowRange = function() {
-    var nextShow = this.data.nextShow;
-    if (nextShow.length > 0){
-        return this.getTime(nextShow[0].start_timestamp) + " - " + this.getTime(nextShow[0].end_timestamp);
-    } else {
-        return "";
-    }
-};
-
-ScheduleData.prototype.getCurrentShowTimeElapsed = function() {
+ScheduleData.prototype.getShowTimeElapsed = function(show) {
     this.secondsTimer();
-    var currentShow = this.data.currentShow;
-    if (currentShow.length > 0){
-        var showStart = this.convertDateToPosixTime(currentShow[0].start_timestamp);
-        return this.convertToHHMMSS(this.estimatedSchedulePosixTime - showStart);
-    } else {
-        return "";
-    }
+
+    var showStart = convertDateToPosixTime(show.getStartTimestamp());
+    return convertToHHMMSS(this.estimatedSchedulePosixTime - showStart);
 };
 
-ScheduleData.prototype.getCurrentShowTimeRemaining = function() {
+ScheduleData.prototype.getShowTimeRemaining = function(show) {
     this.secondsTimer();
-    var currentShow = this.data.currentShow;
-    if (currentShow.length > 0){
-        var showEnd = this.convertDateToPosixTime(currentShow[0].end_timestamp);
-        return this.convertToHHMMSS(showEnd - this.estimatedSchedulePosixTime);
-    } else {
-        return "";
-    }
-};
 
-ScheduleData.prototype.getTime = function(timestamp) {
-    return timestamp.split(" ")[1];
+    var showEnd = convertDateToPosixTime(show.getEndTimestamp());
+    return convertToHHMMSS(showEnd - this.estimatedSchedulePosixTime);
 };
+/* ScheduleData class END */
 
+/* Show class BEGIN */
+function Show(showData){
+    this.showData = showData;
+}
+
+Show.prototype.getName = function(){
+    return this.showData.name;
+}
+Show.prototype.getRange = function(){
+    return getTime(this.showData.start_timestamp) + " - " + getTime(this.showData.end_timestamp);
+}
+Show.prototype.getStartTimestamp = function(){
+    return this.showData.start_timestamp;
+}
+Show.prototype.getEndTimestamp = function(){
+    return this.showData.end_timestamp;
+}
+/* Show class END */
+
+
+function getTime(timestamp) {
+    var time = timestamp.split(" ")[1].split(":");
+    return time[0] + ":" + time[1];
+};
 
 /* Takes an input parameter of milliseconds and converts these into
  * the format HH:MM:SS */
-ScheduleData.prototype.convertToHHMMSS = function(timeInMS){
+function convertToHHMMSS(timeInMS){
 	var time = parseInt(timeInMS);
 
 	var hours = parseInt(time / 3600000);
@@ -189,7 +242,7 @@ ScheduleData.prototype.convertToHHMMSS = function(timeInMS){
 
 /* Takes in a string of format similar to 2011-02-07 02:59:57,
  * and converts this to epoch/posix time. */
-ScheduleData.prototype.convertDateToPosixTime = function(s){
+function convertDateToPosixTime(s){
     var datetime = s.split(" ");
 
     var date = datetime[0].split("-");
diff --git a/public/js/playlist/playlist.js b/public/js/playlist/playlist.js
index 82f277d1c..98b227381 100644
--- a/public/js/playlist/playlist.js
+++ b/public/js/playlist/playlist.js
@@ -169,7 +169,7 @@ function updatePlaybar(){
     	$('#playlist').text(currentShow[0].name);
 
         var recElem = $('.recording-show');
-        currentShow[0].record ? recElem.show(): recElem.hide();
+        (currentShow[0].record == "1") ? recElem.show(): recElem.hide();
     }
 
     $('#show-length').empty();
diff --git a/pypo/install/pypo-install.py b/pypo/install/pypo-install.py
index 07cb43cd9..b764dcec9 100644
--- a/pypo/install/pypo-install.py
+++ b/pypo/install/pypo-install.py
@@ -44,6 +44,8 @@ def create_user(username):
     print "User already exists."
   #add pypo to audio group
   os.system("adduser " + username + " audio 1>/dev/null 2>&1")
+  #add pypo to pulse-access group
+  #os.system("adduser " + username + " pulse-access 1>/dev/null 2>&1")
 
 def copy_dir(src_dir, dest_dir):
   if (os.path.exists(dest_dir)) and (dest_dir != "/"):
diff --git a/python_apps/show-recorder/config.cfg b/python_apps/show-recorder/config.cfg
index f75ea204c..d1bb763ab 100644
--- a/python_apps/show-recorder/config.cfg
+++ b/python_apps/show-recorder/config.cfg
@@ -6,4 +6,4 @@ show_schedule_url = 'Recorder/get-show-schedule/format/json'
 upload_file_url = 'Plupload/upload-recorded/format/json'
 
 # base path to store recordered shows at
-base_recorded_files = '/home/naomi/Music/'
+base_recorded_files = '/home/pypo/Music/'
diff --git a/python_apps/show-recorder/install/recorder-daemontools-logger.sh b/python_apps/show-recorder/install/recorder-daemontools-logger.sh
new file mode 100644
index 000000000..9673575db
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-daemontools-logger.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec setuidgid pypo multilog t ./main
diff --git a/python_apps/show-recorder/install/recorder-daemontools.sh b/python_apps/show-recorder/install/recorder-daemontools.sh
new file mode 100644
index 000000000..d9cec7146
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-daemontools.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+recorder_user="pypo"
+export HOME="/home/pypo/"
+# Location of pypo_cli.py Python script
+recorder_path="/opt/recorder/bin/"
+recorder_script="testrecordscript.py"
+echo "*** Daemontools: starting daemon"
+cd ${recorder_path}
+exec 2>&1
+# Note the -u when calling python! we need it to get unbuffered binary stdout and stderr
+exec sudo python -u ${recorder_path}${recorder_script} -f
+# EOF
diff --git a/python_apps/show-recorder/install/recorder-install.py b/python_apps/show-recorder/install/recorder-install.py
new file mode 100644
index 000000000..1b8186391
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-install.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import time
+import os
+import traceback
+from optparse import *
+import sys
+import time
+import datetime
+import logging
+import logging.config
+import shutil
+import string
+import platform
+from subprocess import Popen, PIPE, STDOUT
+
+if os.geteuid() != 0:
+    print "Please run this as root."
+    sys.exit(1)
+
+BASE_PATH = '/opt/recorder/'
+
+def create_path(path):
+  if not (os.path.exists(path)):
+    print "Creating directory " + path
+    os.makedirs(path)
+
+def create_user(username):
+  print "Checking for user "+username
+  p = Popen('id '+username, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+  output = p.stdout.read()
+  if (output[0:3] != "uid"):
+    # Make the pypo user
+    print "Creating user "+username
+    os.system("adduser --system --quiet --group --shell /bin/bash "+username)
+    
+    #set pypo password
+    p = os.popen('/usr/bin/passwd pypo 1>/dev/null 2>&1', 'w')
+    p.write('pypo\n')
+    p.write('pypo\n')
+    p.close()
+  else:
+    print "User already exists."
+  #add pypo to audio group
+  os.system("adduser " + username + " audio 1>/dev/null 2>&1")
+
+def copy_dir(src_dir, dest_dir):
+  if (os.path.exists(dest_dir)) and (dest_dir != "/"):
+    print "Removing old directory "+dest_dir
+    shutil.rmtree(dest_dir)
+  if not (os.path.exists(dest_dir)):
+    print "Copying directory "+src_dir+" to "+dest_dir
+    shutil.copytree(src_dir, dest_dir)
+                    
+def get_current_script_dir():
+  current_script_dir = os.path.realpath(__file__)
+  index = current_script_dir.rindex('/')
+  print current_script_dir[0:index]
+  return current_script_dir[0:index]
+
+
+try:
+  current_script_dir = get_current_script_dir()
+  print "Checking and removing any existing recorder processes"
+  os.system("python %s/recorder-uninstall.py 1>/dev/null 2>&1"% current_script_dir)
+  time.sleep(5)
+
+  # Create users
+  create_user("pypo")
+
+  print "Creating home directory"
+  create_path("/home/pypo")
+  os.system("chmod -R 755 /home/pypo")
+  os.system("chown -R pypo:pypo /home/pypo")
+
+  print "Creating home directory"
+  create_path("/home/pypo/Music")
+  os.system("chmod -R 755 /home/pypo/Music")
+  os.system("chown -R pypo:pypo /home/pypo/Music")
+
+  print "Creating log directories"
+  create_path("/var/log/recorder")
+  os.system("chmod -R 755 /var/log/recorder")
+  os.system("chown -R pypo:pypo /var/log/recorder")
+
+  create_path(BASE_PATH)
+  create_path(BASE_PATH+"bin")
+  create_path(BASE_PATH+"cache")
+  create_path(BASE_PATH+"files")
+  create_path(BASE_PATH+"tmp")
+  create_path(BASE_PATH+"archive")
+  
+  copy_dir("%s/.."%current_script_dir, BASE_PATH+"bin/")
+  
+  print "Setting permissions"
+  os.system("chmod -R 755 "+BASE_PATH)
+  os.system("chown -R pypo:pypo "+BASE_PATH)
+  
+  print "Installing recorder daemon"
+  create_path("/etc/service/recorder")
+  create_path("/etc/service/recorder/log")
+  shutil.copy("%s/recorder-daemontools.sh"%current_script_dir, "/etc/service/recorder/run")
+  shutil.copy("%s/recorder-daemontools-logger.sh"%current_script_dir, "/etc/service/recorder/log/run")
+  os.system("chmod -R 755 /etc/service/recorder")
+  os.system("chown -R pypo:pypo /etc/service/recorder")
+  
+  print "Waiting for processes to start..."
+  time.sleep(5)
+  os.system("python %s/recorder-start.py" % (get_current_script_dir()))
+  time.sleep(2)
+
+  found = True
+
+  p = Popen('svstat /etc/service/recorder', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+  output = p.stdout.read()
+  if (output.find("unable to open supervise/ok: file does not exist") >= 0):
+    found = False
+  print output
+
+  if not found:
+    print "Recorder install has completed, but daemontools is not running, please make sure you have it installed and then reboot."
+except Exception, e:
+  print "exception:" + str(e)
+  sys.exit(1)
+  
+
+
diff --git a/python_apps/show-recorder/install/recorder-start.py b/python_apps/show-recorder/install/recorder-start.py
new file mode 100644
index 000000000..084b2b1ad
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-start.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+
+if os.geteuid() != 0:
+    print "Please run this as root."
+    sys.exit(1)
+    
+try:
+    print "Starting daemontool script recorder"
+    os.system("svc -u /etc/service/recorder")
+    
+except Exception, e:
+    print "exception:" + str(e)
diff --git a/python_apps/show-recorder/install/recorder-stop.py b/python_apps/show-recorder/install/recorder-stop.py
new file mode 100644
index 000000000..388c0bc4b
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-stop.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+
+if os.geteuid() != 0:
+    print "Please run this as root."
+    sys.exit(1)
+    
+try:
+    print "Stopping daemontool script pypo"
+    os.system("svc -dx /etc/service/pypo 1>/dev/null 2>&1")
+
+    if os.path.exists("/etc/service/pypo-fetch"):
+        os.system("svc -dx /etc/service/pypo-fetch 1>/dev/null 2>&1")
+    if os.path.exists("/etc/service/pypo-push"):
+        os.system("svc -dx /etc/service/pypo-push 1>/dev/null 2>&1")
+ 
+    print "Stopping daemontool script pypo-liquidsoap"
+    os.system("svc -dx /etc/service/pypo-liquidsoap 1>/dev/null 2>&1")
+    os.system("killall liquidsoap")
+    
+except Exception, e:
+    print "exception:" + str(e)
diff --git a/python_apps/show-recorder/install/recorder-uninstall.py b/python_apps/show-recorder/install/recorder-uninstall.py
new file mode 100644
index 000000000..f8ab96432
--- /dev/null
+++ b/python_apps/show-recorder/install/recorder-uninstall.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import time
+
+if os.geteuid() != 0:
+    print "Please run this as root."
+    sys.exit(1)
+    
+BASE_PATH = '/opt/recorder/'
+
+def remove_path(path):
+    os.system("rm -rf " + path)
+
+def remove_user(username):
+    os.system("killall -u %s 1>/dev/null 2>&1" % username)
+    
+    #allow all process to be completely closed before we attempt to delete user
+    print "Waiting for processes to close..."
+    time.sleep(5)
+    
+    os.system("deluser --remove-home " + username + " 1>/dev/null 2>&1")
+
+def get_current_script_dir():
+  current_script_dir = os.path.realpath(__file__)
+  index = current_script_dir.rindex('/')
+  return current_script_dir[0:index]
+    
+try:
+    os.system("python %s/recorder-stop.py" % get_current_script_dir())
+    
+    print "Removing log directories"
+    remove_path("/var/log/recorder")
+    
+    print "Removing recorder files"
+    remove_path(BASE_PATH)
+    
+    print "Removing daemontool script recorder"
+    remove_path("rm -rf /etc/service/recorder")
+
+    remove_user("pypo")
+    print "Uninstall complete."
+except Exception, e:
+    print "exception:" + str(e)
diff --git a/python_apps/show-recorder/testsoundcloud.py b/python_apps/show-recorder/testsoundcloud.py
deleted file mode 100644
index 0ba6fd20d..000000000
--- a/python_apps/show-recorder/testsoundcloud.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import webbrowser
-import scapi
-
-# the host to connect to. Normally, this
-# would be api.soundcloud.com
-API_HOST = "api.soundcloud.com"
-
-# This needs to be the consumer ID you got from
-# http://soundcloud.com/settings/applications/new
-CONSUMER = "2CLCxcSXYzx7QhhPVHN4A"
-# This needs to be the consumer secret password you got from
-# http://soundcloud.com/settings/applications/new
-CONSUMER_SECRET = "pZ7beWmF06epXLHVUP1ufOg2oEnIt9XhE8l8xt0bBs"
-
-# first, we create an OAuthAuthenticator that only knows about consumer
-# credentials. This is done so that we can get an request-token as
-# first step.
-oauth_authenticator = scapi.authentication.OAuthAuthenticator(CONSUMER, 
-                                                              CONSUMER_SECRET,
-                                                              None, 
-                                                              None)
-
-# The connector works with the authenticator to create and sign the requests. It
-# has some helper-methods that allow us to do the OAuth-dance.
-connector = scapi.ApiConnector(host=API_HOST, authenticator=oauth_authenticator)
-
-# First step is to get a request-token, and to let the user authorize that
-# via the browser.
-token, secret = connector.fetch_request_token()
-authorization_url = connector.get_request_token_authorization_url(token)
-webbrowser.open(authorization_url)
-oauth_verifier = raw_input("please enter verifier code as seen in the browser:")
-
-# Now we create a new authenticator with the temporary token & secret we got from
-# the request-token. This will give us the access-token
-oauth_authenticator = scapi.authentication.OAuthAuthenticator(CONSUMER, 
-                                                              CONSUMER_SECRET,
-                                                              token, 
-                                                              secret)
-
-# we need a new connector with the new authenticator!
-connector = scapi.ApiConnector(API_HOST, authenticator=oauth_authenticator)
-token, secret = connector.fetch_access_token(oauth_verifier)
-
-
-# now we are finally ready to go - with all four parameters OAuth requires,
-# we can setup an authenticator that allows for actual API-calls.
-oauth_authenticator = scapi.authentication.OAuthAuthenticator(CONSUMER, 
-                                                              CONSUMER_SECRET,
-                                                              token, 
-                                                              secret)
-
-# we pass the connector to a Scope - a Scope is essentially a path in the REST-url-space.
-# Without any path-component, it's the root from which we can then query into the
-# resources.
-root = scapi.Scope(scapi.ApiConnector(host=API_HOST, authenticator=oauth_authenticator))
-
-# Hey, nice meeting you!  Connected to SoundCloud using OAuth will allow you to access protected resources, like the current user's name.  
-print "Hello, %s" % root.me().username