diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 8a968302c..1045255e0 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -336,7 +336,7 @@ class ApiController extends Zend_Controller_Action $this->view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); - $data = Application_Model_Schedule::GetScheduledPlaylists(); + $data = Application_Model_Schedule::getSchedule(); echo json_encode($data, JSON_FORCE_OBJECT); } diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index 6f02a1467..7e3d94865 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -274,7 +274,7 @@ class ShowbuilderController extends Zend_Controller_Action $opts = array("myShows" => $my_shows, "showFilter" => $show_filter); $showBuilder = new Application_Model_ShowBuilder($startsDT, $endsDT, $opts); - $data = $showBuilder->GetItems(); + $data = $showBuilder->getItems(); $this->view->schedule = $data["schedule"]; $this->view->instances = $data["showInstances"]; $this->view->timestamp = $current_time; diff --git a/airtime_mvc/application/controllers/plugins/RabbitMqPlugin.php b/airtime_mvc/application/controllers/plugins/RabbitMqPlugin.php index c1ea6b1ba..346bfdccc 100644 --- a/airtime_mvc/application/controllers/plugins/RabbitMqPlugin.php +++ b/airtime_mvc/application/controllers/plugins/RabbitMqPlugin.php @@ -5,7 +5,7 @@ class RabbitMqPlugin extends Zend_Controller_Plugin_Abstract public function dispatchLoopShutdown() { if (Application_Model_RabbitMq::$doPush) { - $md = array('schedule' => Application_Model_Schedule::GetScheduledPlaylists()); + $md = array('schedule' => Application_Model_Schedule::getSchedule()); Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md); if (!isset($_SERVER['AIRTIME_SRV'])) { Application_Model_RabbitMq::SendMessageToShowRecorder("update_recorder_schedule"); diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index bd5d98898..a2f563b11 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -132,7 +132,6 @@ class Application_Model_Preference public static function GetHeadTitle() { $title = self::getValue("station_name"); - $defaultNamespace->title = $title; if (strlen($title) > 0) $title .= " - "; diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index a78431bf1..f97b21325 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -511,7 +511,7 @@ SQL; * Returns null if nothing found, else an array of associative * arrays representing each row. */ - public static function GetItems($p_startTime, $p_endTime) + public static function getItems($p_startTime, $p_endTime) { global $CC_CONFIG; @@ -570,7 +570,127 @@ SQL; return $rows; } - public static function GetScheduledPlaylists($p_fromDateTime = null, $p_toDateTime = null) + private static function createInputHarborKickTimes(&$data, $range_start, $range_end) + { + $utcTimeZone = new DateTimeZone("UTC"); + $kick_times = Application_Model_ShowInstance::GetEndTimeOfNextShowWithLiveDJ($range_start, $range_end); + foreach ($kick_times as $kick_time_info) { + $kick_time = $kick_time_info['ends']; + $temp = explode('.', Application_Model_Preference::GetDefaultTransitionFade()); + // we round down transition time since PHP cannot handle millisecond. We need to + // handle this better in the future + $transition_time = intval($temp[0]); + $switchOffDataTime = new DateTime($kick_time, $utcTimeZone); + $switch_off_time = $switchOffDataTime->sub(new DateInterval('PT'.$transition_time.'S')); + $switch_off_time = $switch_off_time->format("Y-m-d H:i:s"); + + $kick_start = self::AirtimeTimeToPypoTime($kick_time); + $data["media"][$kick_start]['start'] = $kick_start; + $data["media"][$kick_start]['end'] = $kick_start; + $data["media"][$kick_start]['event_type'] = "kick_out"; + $data["media"][$kick_start]['type'] = "event"; + $data["media"][$kick_start]['independent_event'] = true; + + if ($kick_time !== $switch_off_time) { + $switch_start = self::AirtimeTimeToPypoTime($switch_off_time); + $data["media"][$switch_start]['start'] = $switch_start; + $data["media"][$switch_start]['end'] = $switch_start; + $data["media"][$switch_start]['event_type'] = "switch_off"; + $data["media"][$switch_start]['independent_event'] = true; + } + } + } + + private static function createFileScheduleEvent(&$data, $item, $media_id) + { + $start = self::AirtimeTimeToPypoTime($item["start"]); + $end = self::AirtimeTimeToPypoTime($item["end"]); + + $schedule_item = array( + 'id' => $media_id, + 'type' => 'file', + 'row_id' => $item["id"], + 'uri' => $uri, + 'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]), + 'fade_out' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_out"]), + 'cue_in' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_in"]), + 'cue_out' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_out"]), + 'start' => $start, + 'end' => $end, + 'show_name' => $showName, + 'replay_gain' => is_null($item["replay_gain"]) ? "0": $item["replay_gain"], + 'independent_event' => true + ); + $data["media"][$start] = $schedule_item; + } + + private static function createStreamScheduleEvent(&$data, $item, $media_id) + { + $start = self::AirtimeTimeToPypoTime($item["start"]); + $end = self::AirtimeTimeToPypoTime($item["end"]); + + //create an event to start stream buffering 5 seconds ahead of the streams actual time. + $buffer_start = new DateTime($item["start"], new DateTimeZone('UTC')); + $buffer_start->sub(new DateInterval("PT5S")); + + $stream_buffer_start = self::AirtimeTimeToPypoTime($buffer_start->format("Y-m-d H:i:s")); + + $schedule_item = array( + 'start' => $stream_buffer_start, + 'end' => $stream_buffer_start, + 'uri' => $uri, + 'row_id' => $item["id"], + 'type' => 'stream_buffer_start', + 'independent_event' => true + ); + + //TODO: Make sure no other media is being overwritten! + $data["media"][$stream_buffer_start] = $schedule_item; + $schedule_item = array( + 'id' => $media_id, + 'type' => 'stream_output_start', + 'row_id' => $item["id"], + 'uri' => $uri, + 'start' => $start, + 'end' => $end, + 'show_name' => $showName, + 'independent_event' => true + ); + $data["media"][$start] = $schedule_item; + + //since a stream never ends we have to insert an additional "kick stream" event. The "start" + //time of this event is the "end" time of the stream minus 1 second. + $dt = new DateTime($item["end"], new DateTimeZone('UTC')); + $dt->sub(new DateInterval("PT1S")); + + //make sure the webstream doesn't play past the end time of the show + if ($dt->getTimestamp() > $showEndDateTime->getTimestamp()) { + $dt = $showEndDateTime; + } + + $stream_end = self::AirtimeTimeToPypoTime($dt->format("Y-m-d H:i:s")); + + $schedule_item = array( + 'start' => $stream_end, + 'end' => $stream_end, + 'uri' => $uri, + 'type' => 'stream_buffer_end', + 'independent_event' => true + ); + $data["media"][$stream_end] = $schedule_item; + + + $schedule_item = array( + 'start' => $stream_end, + 'end' => $stream_end, + 'uri' => $uri, + 'type' => 'stream_output_end', + 'independent_event' => true + ); + $data["media"][$stream_end] = $schedule_item; + } + + private static function getRangeStartAndEnd($p_fromDateTime, $p_toDateTime) { global $CC_CONFIG; @@ -600,8 +720,13 @@ SQL; $range_end = Application_Model_Schedule::PypoTimeToAirtimeTime($p_toDateTime); } - // Scheduler wants everything in a playlist - $items = self::GetItems($range_start, $range_end); + return array($range_start, $range_end); + } + + public static function getSchedule($p_fromDateTime = null, $p_toDateTime = null) + { + + list($range_start, $range_end) = self::getRangeStartAndEnd($p_fromDateTime, $p_toDateTime); $data = array(); $utcTimeZone = new DateTimeZone("UTC"); @@ -609,33 +734,9 @@ SQL; $data["status"] = array(); $data["media"] = array(); - $kick_times = Application_Model_ShowInstance::GetEndTimeOfNextShowWithLiveDJ($range_start, $range_end); - foreach ($kick_times as $kick_time_info) { - $kick_time = $kick_time_info['ends']; - $temp = explode('.', Application_Model_Preference::GetDefaultTransitionFade()); - // we round down transition time since PHP cannot handle millisecond. We need to - // handle this better in the future - $transition_time = intval($temp[0]); - $switchOffDataTime = new DateTime($kick_time, $utcTimeZone); - $switch_off_time = $switchOffDataTime->sub(new DateInterval('PT'.$transition_time.'S')); - $switch_off_time = $switch_off_time->format("Y-m-d H:i:s"); - - $kick_start = Application_Model_Schedule::AirtimeTimeToPypoTime($kick_time); - $data["media"][$kick_start]['start'] = $kick_start; - $data["media"][$kick_start]['end'] = $kick_start; - $data["media"][$kick_start]['event_type'] = "kick_out"; - $data["media"][$kick_start]['type'] = "event"; - $data["media"][$kick_start]['independent_event'] = true; - - if ($kick_time !== $switch_off_time) { - $switch_start = Application_Model_Schedule::AirtimeTimeToPypoTime($switch_off_time); - $data["media"][$switch_start]['start'] = $switch_start; - $data["media"][$switch_start]['end'] = $switch_start; - $data["media"][$switch_start]['event_type'] = "switch_off"; - $data["media"][$switch_start]['independent_event'] = true; - } - } + self::createInputHarborKickTimes($data, $range_start, $range_end); + $items = self::getItems($range_start, $range_end); foreach ($items as $item) { $showInstance = CcShowInstancesQuery::create()->findPK($item["instance_id"]); @@ -648,11 +749,10 @@ SQL; $trackEndDateTime = new DateTime($item["end"], $utcTimeZone); if ($trackStartDateTime->getTimestamp() > $showEndDateTime->getTimestamp()) { + //do not send any tracks that start past their show's end time continue; } - /* Note: cue_out and end are always the same. */ - /* TODO: Not all tracks will have "show_end" */ if ($trackEndDateTime->getTimestamp() > $showEndDateTime->getTimestamp()) { $di = $trackStartDateTime->diff($showEndDateTime); @@ -665,78 +765,37 @@ SQL; $media_id = $item['file_id']; $storedFile = Application_Model_StoredFile::Recall($media_id); $uri = $storedFile->getFilePath(); - $type = "file"; - $independent_event = false; + self::createFileScheduleEvent($data, $item, $media_id, $uri); } elseif (!is_null($item['stream_id'])) { //row is type "webstream" $media_id = $item['stream_id']; $uri = $item['url']; - $type = "stream"; - $independent_event = true; - } - - $start = Application_Model_Schedule::AirtimeTimeToPypoTime($item["start"]); - $end = Application_Model_Schedule::AirtimeTimeToPypoTime($item["end"]); - - $data["media"][$start] = array( - 'id' => $media_id, - 'type' => $type, - 'row_id' => $item["id"], - 'uri' => $uri, - 'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]), - 'fade_out' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_out"]), - 'cue_in' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_in"]), - 'cue_out' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_out"]), - 'start' => $start, - 'end' => $end, - 'show_name' => $showName, - 'replay_gain' => is_null($item["replay_gain"]) ? "0": $item["replay_gain"], - 'independent_event' => $independent_event - ); - - if ($type == "stream") { - //create an event to start stream buffering 5 seconds ahead of the streams actual time. - $buffer_start = new DateTime($item["start"], new DateTimeZone('UTC')); - $buffer_start->sub(new DateInterval("PT5S")); - - $stream_buffer_start = Application_Model_Schedule::AirtimeTimeToPypoTime($buffer_start->format("Y-m-d H:i:s")); - - //TODO: Make sure no other media is being overwritten! - $data["media"][$stream_buffer_start] = array( - 'start' => $stream_buffer_start, - 'end' => $stream_buffer_start, - 'uri' => $uri, - 'row_id' => $item["id"], - 'type' => 'stream_buffer_start', - 'independent_event' => true - ); - - - //since a stream never ends we have to insert an additional "kick stream" event. The "start" - //time of this event is the "end" time of the stream minus 1 second. - $dt = new DateTime($item["end"], new DateTimeZone('UTC')); - $dt->sub(new DateInterval("PT1S")); - - //make sure the webstream doesn't play past the end time of the show - if ($dt->getTimestamp() > $showEndDateTime->getTimestamp()) { - $dt = $showEndDateTime; - } - - $stream_end = Application_Model_Schedule::AirtimeTimeToPypoTime($dt->format("Y-m-d H:i:s")); - - $data["media"][$stream_end] = array( - 'start' => $stream_end, - 'end' => $stream_end, - 'uri' => $uri, - 'type' => 'stream_end', - 'independent_event' => true - ); + self::createStreamScheduleEvent($data, $item, $media_id, $uri); } } - return $data; } + /* + private static function collapseEvents($data) + { + $keys = array_keys($data); + + for ($i = 0, $len = count($keys); $i < $len; $i++) { + $cur = $data[$keys[$i]]; + $next = null; + if ($i+1 < $len) { + $next = $data[$keys[$i+1]]; + } + + if ($cur['type'] == 'stream_buffer_end' && !is_null($next) && $next['type'] == 'stream_buffer_start') { + unset($data[$keys[$i]]); + } + + } + } + */ + public static function deleteAll() { global $CC_CONFIG; diff --git a/airtime_mvc/application/models/ShowBuilder.php b/airtime_mvc/application/models/ShowBuilder.php index ebad18ca3..b73a341d0 100644 --- a/airtime_mvc/application/models/ShowBuilder.php +++ b/airtime_mvc/application/models/ShowBuilder.php @@ -386,7 +386,7 @@ class Application_Model_ShowBuilder return $outdated; } - public function GetItems() + public function getItems() { $current_id = -1; $display_items = array(); diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 312208af8..53ded3e94 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -652,7 +652,7 @@ class Application_Model_StoredFile $displayColumns = array("id", "track_title", "artist_name", "album_title", "genre", "length", "year", "utime", "mtime", "ftype", "track_number", "mood", "bpm", "composer", "info_url", "bit_rate", "sample_rate", "isrc_number", "encoded_by", "label", "copyright", "mime", - "language", "filepath","owner","conductor" + "language", "filepath", "owner", "conductor", "replay_gain" ); //Logging::info($datatables); diff --git a/airtime_mvc/application/models/Webstream.php b/airtime_mvc/application/models/Webstream.php index 22d51a3e8..b1d4b2b77 100644 --- a/airtime_mvc/application/models/Webstream.php +++ b/airtime_mvc/application/models/Webstream.php @@ -178,10 +178,9 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable if (is_null($mime)) { throw new Exception("No MIME type found for webstream."); } - //TODO: return url $mediaUrl = self::getMediaUrl($url, $mime, $content_length_found); - if (preg_match("/(x-mpegurl)|(xspf\+xml)/", $mime)) { + if (preg_match("/(x-mpegurl)|(xspf\+xml)|(pls\+xml)/", $mime)) { list($mime, $content_length_found) = self::discoverStreamMime($mediaUrl); } } catch (Exception $e) { @@ -222,7 +221,7 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable } - private static function getXspfUrl($url) + private static function getUrlData($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); @@ -233,10 +232,17 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable //TODO: What if invalid url? $content = curl_exec($ch); - Logging::info($content); + Logging::debug($content); // close cURL resource, and free up system resources curl_close($ch); + + return $content; + } + + private static function getXspfUrl($url) + { + $content = self::getUrlData($url); $dom = new DOMDocument; //TODO: What if invalid xml? @@ -252,19 +258,23 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable throw new Exception("Could not parse XSPF playlist"); } + + private static function getPlsUrl($url) + { + $content = self::getUrlData($url); + + $ini = parse_ini_string($content, true); + + if ($ini !== false && isset($ini["playlist"]) && isset($ini["playlist"]["File1"])) { + return $ini["playlist"]["File1"]; + } + + throw new Exception("Could not parse PLS playlist"); + } private static function getM3uUrl($url) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - - // grab URL and pass it to the browser - //TODO: What if invalid url? - $content = curl_exec($ch); - Logging::info($content); - curl_close($ch); + $content = self::getUrlData($url); //split into lines: $delim = "\n"; @@ -288,6 +298,8 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable $media_url = self::getM3uUrl($url); } elseif (preg_match("/xspf\+xml/", $mime)) { $media_url = self::getXspfUrl($url); + } elseif (preg_match("/pls\+xml/", $mime)) { + $media_url = self::getPlsUrl($url); } elseif (preg_match("/(mpeg|ogg)/", $mime)) { if ($content_length_found) { throw new Exception("Invalid webstream - This appears to be a file download."); @@ -314,8 +326,6 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable } if (preg_match("/^content-length:/i", $h)) { $content_length_found = true; - //if content-length appears, this is not a web stream!!!! - //Aborting the save process. } } diff --git a/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php b/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php index 9c00c0b68..008c63007 100644 --- a/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php +++ b/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php @@ -100,7 +100,7 @@ class CcFilesTableMap extends TableMap { $this->addColumn('SOUNDCLOUD_ERROR_MSG', 'DbSoundcloudErrorMsg', 'VARCHAR', false, 512, null); $this->addColumn('SOUNDCLOUD_LINK_TO_FILE', 'DbSoundcloudLinkToFile', 'VARCHAR', false, 4096, null); $this->addColumn('SOUNDCLOUD_UPLOAD_TIME', 'DbSoundCloundUploadTime', 'TIMESTAMP', false, 6, null); - $this->addColumn('REPLAY_GAIN', 'DbReplayGain', 'VARCHAR', false, 16, null); + $this->addColumn('REPLAY_GAIN', 'DbReplayGain', 'NUMERIC', false, null, null); $this->addForeignKey('OWNER_ID', 'DbOwnerId', 'INTEGER', 'cc_subjs', 'ID', false, null, null); // validators } // initialize() diff --git a/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php b/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php index 793bab857..0599719ac 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php @@ -1892,20 +1892,29 @@ abstract class BaseCcFilesQuery extends ModelCriteria /** * Filter the query on the replay_gain column * - * @param string $dbReplayGain The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) + * @param string|array $dbReplayGain The value to use as filter. + * Accepts an associative array('min' => $minValue, 'max' => $maxValue) * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return CcFilesQuery The current query, for fluid interface */ public function filterByDbReplayGain($dbReplayGain = null, $comparison = null) { - if (null === $comparison) { - if (is_array($dbReplayGain)) { + if (is_array($dbReplayGain)) { + $useMinMax = false; + if (isset($dbReplayGain['min'])) { + $this->addUsingAlias(CcFilesPeer::REPLAY_GAIN, $dbReplayGain['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($dbReplayGain['max'])) { + $this->addUsingAlias(CcFilesPeer::REPLAY_GAIN, $dbReplayGain['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $dbReplayGain)) { - $dbReplayGain = str_replace('*', '%', $dbReplayGain); - $comparison = Criteria::LIKE; } } return $this->addUsingAlias(CcFilesPeer::REPLAY_GAIN, $dbReplayGain, $comparison); diff --git a/airtime_mvc/application/models/tests/SchedulerTests.php b/airtime_mvc/application/models/tests/SchedulerTests.php index 40235e786..0122ee981 100644 --- a/airtime_mvc/application/models/tests/SchedulerTests.php +++ b/airtime_mvc/application/models/tests/SchedulerTests.php @@ -104,7 +104,7 @@ class SchedulerTests extends PHPUnit_TestCase { $groupId1 = $i1->add('2008-01-01 12:00:00.000', $this->storedFile->getId()); $i2 = new Application_Model_ScheduleGroup(); $i2->addAfter($groupId1, $this->storedFile->getId()); - $items = Application_Model_Schedule::GetItems("2008-01-01", "2008-01-02"); + $items = Application_Model_Schedule::getItems("2008-01-01", "2008-01-02"); if (count($items) != 2) { $this->fail("Wrong number of items returned."); return; diff --git a/airtime_mvc/application/models/tests/populator.php b/airtime_mvc/application/models/tests/populator.php index 1ad1b2806..3b85d76bb 100644 --- a/airtime_mvc/application/models/tests/populator.php +++ b/airtime_mvc/application/models/tests/populator.php @@ -99,7 +99,7 @@ while ($showTime < $endDate) { } if (Application_Model_RabbitMq::$doPush) { - $md = array('schedule' => Application_Model_Schedule::GetScheduledPlaylists()); + $md = array('schedule' => Application_Model_Schedule::getSchedule()); Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md); } diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index b03e14011..b9899cca8 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -74,7 +74,7 @@ - + diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index 4fd4c1c45..cc47701c6 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -92,7 +92,7 @@ CREATE TABLE "cc_files" "soundcloud_error_msg" VARCHAR(512), "soundcloud_link_to_file" VARCHAR(4096), "soundcloud_upload_time" TIMESTAMP(6), - "replay_gain" VARCHAR(16), + "replay_gain" NUMERIC, "owner_id" INTEGER, PRIMARY KEY ("id") ); @@ -633,7 +633,7 @@ CREATE TABLE "cc_webstream" "id" serial NOT NULL, "name" VARCHAR(255) NOT NULL, "description" VARCHAR(255) NOT NULL, - "url" VARCHAR(255) NOT NULL, + "url" VARCHAR(512) NOT NULL, "length" interval default '00:00:00' NOT NULL, "creator_id" INTEGER NOT NULL, "mtime" TIMESTAMP(6) NOT NULL, diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index b648c6acc..ba7c0f574 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -36,7 +36,8 @@ var AIRTIME = (function(AIRTIME) { "track_title" : "s", "track_num" : "n", "year" : "n", - "owner" : "s" + "owner" : "s", + "replay_gain" : "n" }; if (AIRTIME.library === undefined) { @@ -414,7 +415,8 @@ var AIRTIME = (function(AIRTIME) { /* Mime */ { "sTitle" : "Mime" , "mDataProp" : "mime" , "bVisible" : false , "sClass" : "library_mime" , "sWidth" : "80px" } , /* Language */ { "sTitle" : "Language" , "mDataProp" : "language" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" } , /* Owner */ { "sTitle" : "Owner" , "mDataProp" : "owner" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" } , - /* Conductor */ { "sTitle" : "Conductor" , "mDataProp" : "conductor" , "bVisible" : false , "sClass" : "library_conductor" , "sWidth" : "125px" } + /* Conductor */ { "sTitle" : "Conductor" , "mDataProp" : "conductor" , "bVisible" : false , "sClass" : "library_conductor" , "sWidth" : "125px" }, + /* Replay Gain */ { "sTitle" : "Replay Gain" , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" } ], "bProcessing": true, diff --git a/install_full/ubuntu/airtime-full-install b/install_full/ubuntu/airtime-full-install index af135b124..57faff468 100755 --- a/install_full/ubuntu/airtime-full-install +++ b/install_full/ubuntu/airtime-full-install @@ -52,7 +52,8 @@ php-pear php5-gd postgresql odbc-postgresql python libsoundtouch-ocaml \ libtaglib-ocaml libao-ocaml libmad-ocaml ecasound \ libesd0 libportaudio2 libsamplerate0 rabbitmq-server patch \ php5-curl mpg123 monit python-virtualenv multitail libcamomile-ocaml-data \ -libpulse0 vorbis-tools lsb-release lsof sudo mp3gain vorbisgain flac vorbis-tools +libpulse0 vorbis-tools lsb-release lsof sudo mp3gain vorbisgain flac vorbis-tools \ +pwgen #install packages with --force-yes option (this is useful in the case #of Debian, where these packages are unauthorized) diff --git a/install_full/ubuntu/airtime-full-install-nginx b/install_full/ubuntu/airtime-full-install-nginx index c89e81198..c00e3f159 100755 --- a/install_full/ubuntu/airtime-full-install-nginx +++ b/install_full/ubuntu/airtime-full-install-nginx @@ -43,7 +43,8 @@ php-pear php5-gd postgresql odbc-postgresql python libsoundtouch-ocaml \ libtaglib-ocaml libao-ocaml libmad-ocaml ecasound \ libesd0 libportaudio2 libsamplerate0 rabbitmq-server patch \ php5-curl mpg123 monit python-virtualenv multitail libcamomile-ocaml-data \ -libpulse0 vorbis-tools lsb-release lsof sudo mp3gain vorbisgain flac vorbis-tools +libpulse0 vorbis-tools lsb-release lsof sudo mp3gain vorbisgain flac vorbis-tools \ +pwgen #install packages with --force-yes option (this is useful in the case #of Debian, where these packages are unauthorized) diff --git a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq index a3b3fc319..085d03661 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq @@ -393,7 +393,7 @@ end dyn_out = output.icecast(%wav, host="localhost", port=8999, - password="hackme", + password=stream_harbor_pass, mount="test-harbor", fallible=true) @@ -406,7 +406,7 @@ end # Function to create a playlist source and output it. def create_dynamic_source(uri) = # The playlist source - s = input.http(buffer=2., max=12., uri) + s = audio_to_stereo(input.http(buffer=2., max=12., uri)) # The output active_dyn_out = dyn_out(s) diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq index b7a6d41d7..7b04210b4 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq @@ -36,9 +36,11 @@ s2_namespace = ref '' s3_namespace = ref '' just_switched = ref false +stream_harbor_pass = list.hd(get_process_lines('pwgen -s -N 1 -n 20')) + %include "ls_lib.liq" -web_stream = input.harbor("test-harbor", port=8999, password="hackme") +web_stream = input.harbor("test-harbor", port=8999, password=stream_harbor_pass) web_stream = on_metadata(notify_stream, web_stream) queue = on_metadata(notify, queue) diff --git a/python_apps/pypo/pypopush.py b/python_apps/pypo/pypopush.py index d11b52a50..5a5350823 100644 --- a/python_apps/pypo/pypopush.py +++ b/python_apps/pypo/pypopush.py @@ -40,7 +40,7 @@ except Exception, e: sys.exit() def is_stream(media_item): - return media_item['type'] == 'stream' + return media_item['type'] == 'stream_output_start' def is_file(media_item): return media_item['type'] == 'file' @@ -211,7 +211,7 @@ class PypoPush(Thread): queue. """ file_chain = filter(lambda item: (item["type"] == "file"), current_event_chain) - stream_chain = filter(lambda item: (item["type"] == "stream"), current_event_chain) + stream_chain = filter(lambda item: (item["type"] == "stream_output_start"), current_event_chain) self.logger.debug(self.current_stream_info) self.logger.debug(current_event_chain) @@ -427,13 +427,13 @@ class PypoPush(Thread): PypoFetch.switch_source(self.logger, self.telnet_lock, "live_dj", "off") elif media_item['type'] == 'stream_buffer_start': self.start_web_stream_buffer(media_item) - elif media_item['type'] == "stream": + elif media_item['type'] == "stream_output_start": if media_item['row_id'] != self.current_prebuffering_stream_id: #this is called if the stream wasn't scheduled sufficiently ahead of time #so that the prebuffering stage could take effect. Let's do the prebuffering now. self.start_web_stream_buffer(media_item) self.start_web_stream(media_item) - elif media_item['type'] == "stream_end": + elif media_item['type'] == "stream_buffer_end": self.stop_web_stream(media_item) except Exception, e: self.logger.error('Pypo Push Exception: %s', e) diff --git a/python_apps/pypo/test/airtime-schedule-insert.php b/python_apps/pypo/test/airtime-schedule-insert.php index 70c1f38c7..fe2dc97fe 100644 --- a/python_apps/pypo/test/airtime-schedule-insert.php +++ b/python_apps/pypo/test/airtime-schedule-insert.php @@ -78,7 +78,7 @@ echo "Removing everything from the scheduler between $startTime and $endTime..." $scheduleClear = Schedule::isScheduleEmptyInRange($startTime, "01:00:00"); if (!$scheduleClear) { echo "\nERROR: Schedule could not be cleared.\n\n"; - var_dump(Schedule::GetItems($startTime, $endTime)); + var_dump(Schedule::getItems($startTime, $endTime)); exit; } echo "done.\n";