Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
denise 2012-08-07 11:08:34 -04:00
commit d05661afff
26 changed files with 244 additions and 160 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "python_apps/pypo/liquidsoap_bin"]
path = python_apps/pypo/liquidsoap_bin
url = git://github.com/sourcefabric/airtime-liquidsoap.git

View File

@ -258,29 +258,39 @@ class ApiController extends Zend_Controller_Action
$request = $this->getRequest(); $request = $this->getRequest();
$type = $request->getParam('type'); $type = $request->getParam('type');
/* This is some *extremely* lazy programming that needs to bi fixed. For some reason
* we are using two entirely different codepaths for very similar functionality (type = endofday
* vs type = interval). Needs to be fixed for 2.2 - MK */
if ($type == "endofday") { if ($type == "endofday") {
$limit = $request->getParam('limit'); $limit = $request->getParam('limit');
if($limit == "" || !is_numeric($limit)) { if ($limit == "" || !is_numeric($limit)) {
$limit = "5"; $limit = "5";
} }
// make GetNextShows use end of day // make getNextShows use end of day
$utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc(); $utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc();
$result = array("env"=>APPLICATION_ENV, $result = array("env"=>APPLICATION_ENV,
"schedulerTime"=>gmdate("Y-m-d H:i:s"), "schedulerTime"=>gmdate("Y-m-d H:i:s"),
"nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd)); "currentShow"=>Application_Model_Show::getCurrentShow($utcTimeNow),
"nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd)
);
Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); Application_Model_Show::convertToLocalTimeZone($result["currentShow"],
array("starts", "ends", "start_timestamp", "end_timestamp"));
Application_Model_Show::convertToLocalTimeZone($result["nextShow"],
array("starts", "ends", "start_timestamp", "end_timestamp"));
} else { } else {
$result = Application_Model_Schedule::GetPlayOrderRange(); $result = Application_Model_Schedule::GetPlayOrderRange();
//Convert from UTC to localtime for Web Browser. //Convert from UTC to localtime for Web Browser.
Application_Model_Show::convertToLocalTimeZone($result["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); Application_Model_Show::ConvertToLocalTimeZone($result["currentShow"],
Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); array("starts", "ends", "start_timestamp", "end_timestamp"));
Application_Model_Show::ConvertToLocalTimeZone($result["nextShow"],
array("starts", "ends", "start_timestamp", "end_timestamp"));
} }
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; //used by caller to determine if the airtime they are running or widgets in use is out of date. //used by caller to determine if the airtime they are running or widgets in use is out of date.
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
header("Content-type: text/javascript"); header("Content-type: text/javascript");
// If a callback is not given, then just provide the raw JSON. // If a callback is not given, then just provide the raw JSON.

View File

@ -7,6 +7,7 @@ class WebstreamController extends Zend_Controller_Action
$ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('new', 'json') $ajaxContext->addActionContext('new', 'json')
->addActionContext('save', 'json') ->addActionContext('save', 'json')
->addActionContext('edit', 'json')
->initContext(); ->initContext();
//TODO //TODO
//$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME); //$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME);
@ -29,14 +30,52 @@ class WebstreamController extends Zend_Controller_Action
*/ */
} }
public function editAction()
{
$request = $this->getRequest();
$id = $request->getParam("id");
if (is_null($id)) {
throw new Exception("Missing parameter 'id'");
}
$this->view->ws = new Application_Model_Webstream($id);
$this->view->html = $this->view->render('webstream/webstream.phtml');
}
public function saveAction() public function saveAction()
{ {
$request = $this->getRequest(); $request = $this->getRequest();
$user = Application_Model_User::getCurrentUser();
$hasPermission = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST));
$id = $request->getParam("id");
if ($id == -1) {
$webstream = new CcWebstream();
} else {
$webstream = CcWebstreamQuery::create()->findPK($id);
}
if ($id != -1) {
//we are updating a playlist. Ensure that if the user is a host/dj, that he has the correct permission.
$user = Application_Model_User::getCurrentUser();
if ($webstream->getDbCreatorId() != $user->getId()) {
header("Status: 401 Not Authorized");
return;
}
}
if (!$hasPermission) {
header("Status: 401 Not Authorized");
return;
}
$analysis = Application_Model_Webstream::analyzeFormData($request); $analysis = Application_Model_Webstream::analyzeFormData($request);
if (Application_Model_Webstream::isValid($analysis)) { if (Application_Model_Webstream::isValid($analysis)) {
Application_Model_Webstream::save($request); Application_Model_Webstream::save($request, $webstream);
$this->view->statusMessage = "<div class='success'>Webstream saved.</div>"; $this->view->statusMessage = "<div class='success'>Webstream saved.</div>";
} else { } else {
$this->view->statusMessage = "<div class='errors'>Invalid form values.</div>"; $this->view->statusMessage = "<div class='errors'>Invalid form values.</div>";

View File

@ -107,8 +107,7 @@ class Application_Model_Schedule
$sql = "SELECT * FROM (($filesSql) UNION ($streamSql)) AS unioned ORDER BY starts"; $sql = "SELECT * FROM (($filesSql) UNION ($streamSql)) AS unioned ORDER BY starts";
$rows = $con->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$rows = $con->query($sql)->fetchAll();
$numberOfRows = count($rows); $numberOfRows = count($rows);
$results['previous'] = null; $results['previous'] = null;

View File

@ -1763,8 +1763,7 @@ class Application_Model_Show
." AND modified_instance != TRUE"; ." AND modified_instance != TRUE";
// Convert back to local timezone // Convert back to local timezone
$rows = $con->query($sql)->fetchAll(); $rows = $con->query($sql)->fetchAll(PDO::FETCH_ASSOC);
return $rows; return $rows;
} }
@ -1894,7 +1893,7 @@ class Application_Model_Show
} }
//TODO, returning starts + ends twice (once with an alias). Unify this after the 2.0 release. --Martin //TODO, returning starts + ends twice (once with an alias). Unify this after the 2.0 release. --Martin
$sql = "SELECT *, si.starts as start_timestamp, si.ends as end_timestamp FROM " $sql = "SELECT si.starts as start_timestamp, si.ends as end_timestamp, s.name, s.id, si.id as instance_id, si.record, s.url, starts, ends"
." $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s" ." $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s"
." WHERE si.show_id = s.id" ." WHERE si.show_id = s.id"
." AND si.starts >= TIMESTAMP '$timeStart'" ." AND si.starts >= TIMESTAMP '$timeStart'"
@ -1907,8 +1906,7 @@ class Application_Model_Show
$sql = $sql . " LIMIT $limit"; $sql = $sql . " LIMIT $limit";
} }
$rows = $con->query($sql)->fetchAll(); $rows = $con->query($sql)->fetchAll(PDO::FETCH_ASSOC);
return $rows; return $rows;
} }

View File

@ -606,7 +606,7 @@ class Application_Model_StoredFile
$plSelect[] = "PL.id AS ".$key; $plSelect[] = "PL.id AS ".$key;
$blSelect[] = "BL.id AS ".$key; $blSelect[] = "BL.id AS ".$key;
$fileSelect[] = $key; $fileSelect[] = $key;
$streamSelect[] = $key; $streamSelect[] = "ws.id AS ".$key;
} elseif ($key === "track_title") { } elseif ($key === "track_title") {
$plSelect[] = "name AS ".$key; $plSelect[] = "name AS ".$key;
$blSelect[] = "name AS ".$key; $blSelect[] = "name AS ".$key;
@ -621,7 +621,7 @@ class Application_Model_StoredFile
$plSelect[] = "login AS ".$key; $plSelect[] = "login AS ".$key;
$blSelect[] = "login AS ".$key; $blSelect[] = "login AS ".$key;
$fileSelect[] = $key; $fileSelect[] = $key;
$streamSelect[] = "creator_id AS ".$key; $streamSelect[] = "login AS ".$key;
} }
//same columns in each table. //same columns in each table.
else if (in_array($key, array("length", "utime", "mtime"))) { else if (in_array($key, array("length", "utime", "mtime"))) {
@ -659,7 +659,7 @@ class Application_Model_StoredFile
$plTable = "({$plSelect} FROM cc_playlist AS PL LEFT JOIN cc_subjs AS sub ON (sub.id = PL.creator_id))"; $plTable = "({$plSelect} FROM cc_playlist AS PL LEFT JOIN cc_subjs AS sub ON (sub.id = PL.creator_id))";
$blTable = "({$blSelect} FROM cc_block AS BL LEFT JOIN cc_subjs AS sub ON (sub.id = BL.creator_id))"; $blTable = "({$blSelect} FROM cc_block AS BL LEFT JOIN cc_subjs AS sub ON (sub.id = BL.creator_id))";
$fileTable = "({$fileSelect} FROM cc_files AS FILES WHERE file_exists = 'TRUE')"; $fileTable = "({$fileSelect} FROM cc_files AS FILES WHERE file_exists = 'TRUE')";
$streamTable = "({$streamSelect} FROM cc_webstream AS WEBSTREAM)"; $streamTable = "({$streamSelect} FROM cc_webstream AS ws LEFT JOIN cc_subjs AS sub ON (sub.id = ws.creator_id))";
$unionTable = "({$plTable} UNION {$blTable} UNION {$fileTable} UNION {$streamTable}) AS RESULTS"; $unionTable = "({$plTable} UNION {$blTable} UNION {$fileTable} UNION {$streamTable}) AS RESULTS";
//choose which table we need to select data from. //choose which table we need to select data from.
@ -676,6 +676,9 @@ class Application_Model_StoredFile
case 3: case 3:
$fromTable = $blTable." AS Block"; //need an alias for the table if it's standalone. $fromTable = $blTable." AS Block"; //need an alias for the table if it's standalone.
break; break;
case 4:
$fromTable = $streamTable." AS StreamTable"; //need an alias for the table if it's standalone.
break;
default: default:
$fromTable = $unionTable; $fromTable = $unionTable;
} }
@ -696,7 +699,7 @@ class Application_Model_StoredFile
$formatter = new BitrateFormatter($row['bit_rate']); $formatter = new BitrateFormatter($row['bit_rate']);
$row['bit_rate'] = $formatter->format(); $row['bit_rate'] = $formatter->format();
} }
//convert mtime and utime to localtime //convert mtime and utime to localtime
$row['mtime'] = new DateTime($row['mtime'], new DateTimeZone('UTC')); $row['mtime'] = new DateTime($row['mtime'], new DateTimeZone('UTC'));
$row['mtime']->setTimeZone(new DateTimeZone(date_default_timezone_get())); $row['mtime']->setTimeZone(new DateTimeZone(date_default_timezone_get()));

View File

@ -4,34 +4,59 @@ class Application_Model_Webstream{
private $id; private $id;
public function __construct($id) public function __construct($id=-1)
{ {
$this->id = $id; if ($id == -1) {
$this->webstream = new CcWebstream();
//We're not saving this object in the database, so -1 ID is OK.
$this->webstream->setDbId(-1);
$this->webstream->setDbName("Untitled Webstream");
$this->webstream->setDbDescription("");
$this->webstream->setDbUrl("http://");
$this->webstream->setDbLength("00:00:00");
$this->webstream->setDbName("Untitled Webstream");
} else {
$this->id = $id;
$this->webstream = CcWebstreamQuery::create()->findPK($this->id);
}
} }
public static function getName() public function getName()
{ {
return "Default"; return $this->webstream->getDbName();
} }
public static function getId() public function getId()
{ {
return "id"; return $this->webstream->getDbId();
} }
public static function getLastModified($p_type) public function getLastModified($p_type)
{ {
return "modified"; return "modified";
} }
public static function getDefaultLength() public function getDefaultLength()
{ {
return "length"; $dateString = $this->webstream->getDbLength();
$arr = explode(":", $dateString);
if (count($arr) == 3) {
list($hours, $min, $sec) = $arr;
$di = new DateInterval("PT{$hours}H{$min}M{$sec}S");
return $di->format("%Hh %Im");
}
return "";
} }
public static function getDescription() public function getDescription()
{ {
return "desc"; return $this->webstream->getDbDescription();
}
public function getUrl()
{
return $this->webstream->getDbUrl();
} }
public function getMetadata() public function getMetadata()
@ -41,11 +66,11 @@ class Application_Model_Webstream{
$username = $subjs->getDbLogin(); $username = $subjs->getDbLogin();
return array( return array(
"name" => $webstream->getDbName(), "name" => $this->webstream->getDbName(),
"length" => $webstream->getDbLength(), "length" => $this->webstream->getDbLength(),
"description" => $webstream->getDbDescription(), "description" => $this->webstream->getDbDescription(),
"login"=> $username, "login"=> $username,
"url" => $webstream->getDbUrl(), "url" => $this->webstream->getDbUrl(),
); );
} }
@ -75,25 +100,12 @@ class Application_Model_Webstream{
return $leftOvers; return $leftOvers;
} }
/*
Array
(
[controller] => Webstream
[action] => save
[module] => default
[format] => json
[description] => desc
[url] => http://
[length] => 00h 20m
[name] => Default
)
*/
public static function analyzeFormData($request) public static function analyzeFormData($request)
{ {
$valid = array("length" => array(true, ''), $valid = array("length" => array(true, ''),
"url" => array(true, '')); "url" => array(true, ''),
"name" => array(true, ''));
$length = trim($request->getParam("length")); $length = trim($request->getParam("length"));
$result = preg_match("/^([0-9]{1,2})h ([0-5][0-9])m$/", $length, $matches); $result = preg_match("/^([0-9]{1,2})h ([0-5][0-9])m$/", $length, $matches);
@ -120,6 +132,19 @@ Array
$valid['name'][1] = 'Webstream name cannot be empty'; $valid['name'][1] = 'Webstream name cannot be empty';
} }
$id = trim($request->getParam("id"));
if (!is_null($id)) {
// user has performed a create stream action instead of edit
// stream action. Check if user has the rights to edit this stream.
Logging::log("CREATE");
} else {
Logging::log("EDIT");
}
return $valid; return $valid;
} }
@ -134,12 +159,13 @@ Array
return true; return true;
} }
public static function save($request) public static function save($request, $webstream)
{ {
$userInfo = Zend_Auth::getInstance()->getStorage()->read(); $userInfo = Zend_Auth::getInstance()->getStorage()->read();
$length = trim($request->getParam("length")); $length = trim($request->getParam("length"));
$result = preg_match("/^([0-9]{1,2})h ([0-5][0-9])m$/", $length, $matches); $result = preg_match("/^([0-9]{1,2})h ([0-5][0-9])m$/", $length, $matches);
if ($result == 1 && count($matches) == 3) { if ($result == 1 && count($matches) == 3) {
$hours = $matches[1]; $hours = $matches[1];
$minutes = $matches[2]; $minutes = $matches[2];
@ -150,9 +176,8 @@ Array
//in the controller //in the controller
throw new Exception("Invalid date format: $length"); throw new Exception("Invalid date format: $length");
} }
#TODO: These should be validated by a Zend Form.
$webstream = new CcWebstream();
$webstream->setDbName($request->getParam("name")); $webstream->setDbName($request->getParam("name"));
$webstream->setDbDescription($request->getParam("description")); $webstream->setDbDescription($request->getParam("description"));
$webstream->setDbUrl($request->getParam("url")); $webstream->setDbUrl($request->getParam("url"));

View File

@ -43,7 +43,7 @@ class CcWebstreamTableMap extends TableMap {
$this->addColumn('DESCRIPTION', 'DbDescription', 'VARCHAR', true, 255, null); $this->addColumn('DESCRIPTION', 'DbDescription', 'VARCHAR', true, 255, null);
$this->addColumn('URL', 'DbUrl', 'VARCHAR', true, 255, null); $this->addColumn('URL', 'DbUrl', 'VARCHAR', true, 255, null);
$this->addColumn('LENGTH', 'DbLength', 'VARCHAR', true, null, '00:00:00'); $this->addColumn('LENGTH', 'DbLength', 'VARCHAR', true, null, '00:00:00');
$this->addColumn('CREATOR_ID', 'DbCreatorId', 'VARCHAR', true, 255, null); $this->addColumn('CREATOR_ID', 'DbCreatorId', 'INTEGER', true, null, null);
$this->addColumn('MTIME', 'DbMtime', 'TIMESTAMP', true, 6, null); $this->addColumn('MTIME', 'DbMtime', 'TIMESTAMP', true, 6, null);
$this->addColumn('UTIME', 'DbUtime', 'TIMESTAMP', true, 6, null); $this->addColumn('UTIME', 'DbUtime', 'TIMESTAMP', true, 6, null);
// validators // validators

View File

@ -57,7 +57,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent
/** /**
* The value for the creator_id field. * The value for the creator_id field.
* @var string * @var int
*/ */
protected $creator_id; protected $creator_id;
@ -166,7 +166,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent
/** /**
* Get the [creator_id] column value. * Get the [creator_id] column value.
* *
* @return string * @return int
*/ */
public function getDbCreatorId() public function getDbCreatorId()
{ {
@ -342,13 +342,13 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent
/** /**
* Set the value of [creator_id] column. * Set the value of [creator_id] column.
* *
* @param string $v new value * @param int $v new value
* @return CcWebstream The current object (for fluent API support) * @return CcWebstream The current object (for fluent API support)
*/ */
public function setDbCreatorId($v) public function setDbCreatorId($v)
{ {
if ($v !== null) { if ($v !== null) {
$v = (string) $v; $v = (int) $v;
} }
if ($this->creator_id !== $v) { if ($this->creator_id !== $v) {
@ -498,7 +498,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent
$this->description = ($row[$startcol + 2] !== null) ? (string) $row[$startcol + 2] : null; $this->description = ($row[$startcol + 2] !== null) ? (string) $row[$startcol + 2] : null;
$this->url = ($row[$startcol + 3] !== null) ? (string) $row[$startcol + 3] : null; $this->url = ($row[$startcol + 3] !== null) ? (string) $row[$startcol + 3] : null;
$this->length = ($row[$startcol + 4] !== null) ? (string) $row[$startcol + 4] : null; $this->length = ($row[$startcol + 4] !== null) ? (string) $row[$startcol + 4] : null;
$this->creator_id = ($row[$startcol + 5] !== null) ? (string) $row[$startcol + 5] : null; $this->creator_id = ($row[$startcol + 5] !== null) ? (int) $row[$startcol + 5] : null;
$this->mtime = ($row[$startcol + 6] !== null) ? (string) $row[$startcol + 6] : null; $this->mtime = ($row[$startcol + 6] !== null) ? (string) $row[$startcol + 6] : null;
$this->utime = ($row[$startcol + 7] !== null) ? (string) $row[$startcol + 7] : null; $this->utime = ($row[$startcol + 7] !== null) ? (string) $row[$startcol + 7] : null;
$this->resetModified(); $this->resetModified();

View File

@ -40,7 +40,7 @@
* @method CcWebstream findOneByDbDescription(string $description) Return the first CcWebstream filtered by the description column * @method CcWebstream findOneByDbDescription(string $description) Return the first CcWebstream filtered by the description column
* @method CcWebstream findOneByDbUrl(string $url) Return the first CcWebstream filtered by the url column * @method CcWebstream findOneByDbUrl(string $url) Return the first CcWebstream filtered by the url column
* @method CcWebstream findOneByDbLength(string $length) Return the first CcWebstream filtered by the length column * @method CcWebstream findOneByDbLength(string $length) Return the first CcWebstream filtered by the length column
* @method CcWebstream findOneByDbCreatorId(string $creator_id) Return the first CcWebstream filtered by the creator_id column * @method CcWebstream findOneByDbCreatorId(int $creator_id) Return the first CcWebstream filtered by the creator_id column
* @method CcWebstream findOneByDbMtime(string $mtime) Return the first CcWebstream filtered by the mtime column * @method CcWebstream findOneByDbMtime(string $mtime) Return the first CcWebstream filtered by the mtime column
* @method CcWebstream findOneByDbUtime(string $utime) Return the first CcWebstream filtered by the utime column * @method CcWebstream findOneByDbUtime(string $utime) Return the first CcWebstream filtered by the utime column
* *
@ -49,7 +49,7 @@
* @method array findByDbDescription(string $description) Return CcWebstream objects filtered by the description column * @method array findByDbDescription(string $description) Return CcWebstream objects filtered by the description column
* @method array findByDbUrl(string $url) Return CcWebstream objects filtered by the url column * @method array findByDbUrl(string $url) Return CcWebstream objects filtered by the url column
* @method array findByDbLength(string $length) Return CcWebstream objects filtered by the length column * @method array findByDbLength(string $length) Return CcWebstream objects filtered by the length column
* @method array findByDbCreatorId(string $creator_id) Return CcWebstream objects filtered by the creator_id column * @method array findByDbCreatorId(int $creator_id) Return CcWebstream objects filtered by the creator_id column
* @method array findByDbMtime(string $mtime) Return CcWebstream objects filtered by the mtime column * @method array findByDbMtime(string $mtime) Return CcWebstream objects filtered by the mtime column
* @method array findByDbUtime(string $utime) Return CcWebstream objects filtered by the utime column * @method array findByDbUtime(string $utime) Return CcWebstream objects filtered by the utime column
* *
@ -269,20 +269,29 @@ abstract class BaseCcWebstreamQuery extends ModelCriteria
/** /**
* Filter the query on the creator_id column * Filter the query on the creator_id column
* *
* @param string $dbCreatorId The value to use as filter. * @param int|array $dbCreatorId The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE) * Accepts an associative array('min' => $minValue, 'max' => $maxValue)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
* *
* @return CcWebstreamQuery The current query, for fluid interface * @return CcWebstreamQuery The current query, for fluid interface
*/ */
public function filterByDbCreatorId($dbCreatorId = null, $comparison = null) public function filterByDbCreatorId($dbCreatorId = null, $comparison = null)
{ {
if (null === $comparison) { if (is_array($dbCreatorId)) {
if (is_array($dbCreatorId)) { $useMinMax = false;
if (isset($dbCreatorId['min'])) {
$this->addUsingAlias(CcWebstreamPeer::CREATOR_ID, $dbCreatorId['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($dbCreatorId['max'])) {
$this->addUsingAlias(CcWebstreamPeer::CREATOR_ID, $dbCreatorId['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
return $this;
}
if (null === $comparison) {
$comparison = Criteria::IN; $comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $dbCreatorId)) {
$dbCreatorId = str_replace('*', '%', $dbCreatorId);
$comparison = Criteria::LIKE;
} }
} }
return $this->addUsingAlias(CcWebstreamPeer::CREATOR_ID, $dbCreatorId, $comparison); return $this->addUsingAlias(CcWebstreamPeer::CREATOR_ID, $dbCreatorId, $comparison);

View File

@ -26,12 +26,12 @@
<div id="url-error" class="errors" style="display:none;"></div> <div id="url-error" class="errors" style="display:none;"></div>
<dt id="streamurl-label"><label for="streamurl">Stream URL:</label></dt> <dt id="streamurl-label"><label for="streamurl">Stream URL:</label></dt>
<dd id="streamurl-element"> <dd id="streamurl-element">
<input type="text" value="http://" size="40"/> <input type="text" value="<?php echo $this->ws->getUrl(); ?>" size="40"/>
</dd> </dd>
<div id="length-error" class="errors" style="display:none;"></div> <div id="length-error" class="errors" style="display:none;"></div>
<dt id="streamlength-label"><label for="streamlength">Default Length:</label></dt> <dt id="streamlength-label"><label for="streamlength">Default Length:</label></dt>
<dd id="streamlength-element"> <dd id="streamlength-element">
<input type="text" value="00h 20m"/> <input type="text" value="<?php echo $this->ws->getDefaultLength() ?>"/>
</dd> </dd>
<dd id="submit-element" class="buttons"> <dd id="submit-element" class="buttons">
<input class="ui-button ui-state-default" type="submit" value="Save" id="webstream_save" name="submit"> <input class="ui-button ui-state-default" type="submit" value="Save" id="webstream_save" name="submit">

View File

@ -419,7 +419,7 @@
<column name="description" phpName="DbDescription" type="VARCHAR" size="255" required="true" /> <column name="description" phpName="DbDescription" type="VARCHAR" size="255" required="true" />
<column name="url" phpName="DbUrl" type="VARCHAR" size="255" required="true" /> <column name="url" phpName="DbUrl" type="VARCHAR" size="255" required="true" />
<column name="length" phpName="DbLength" type="VARCHAR" sqlType="interval" required="true" defaultValue="00:00:00"/> <column name="length" phpName="DbLength" type="VARCHAR" sqlType="interval" required="true" defaultValue="00:00:00"/>
<column name="creator_id" phpName="DbCreatorId" type="VARCHAR" size="255" required="true" /> <column name="creator_id" phpName="DbCreatorId" type="INTEGER" required="true" />
<column name="mtime" phpName="DbMtime" type="TIMESTAMP" size="6" required="true" /> <column name="mtime" phpName="DbMtime" type="TIMESTAMP" size="6" required="true" />
<column name="utime" phpName="DbUtime" type="TIMESTAMP" size="6" required="true" /> <column name="utime" phpName="DbUtime" type="TIMESTAMP" size="6" required="true" />
</table> </table>

View File

@ -1,9 +1,9 @@
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin')); INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
-- added in 2.2 -- added in 2.2
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s1_name', 'Airtime!', 'string'); -- INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s1_name', 'Airtime!', 'string');
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s2_name', '', 'string'); -- INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s2_name', '', 'string');
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_name', '', 'string'); -- INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_name', '', 'string');
-- end of added in 2.2 -- end of added in 2.2
-- added in 2.1 -- added in 2.1

View File

@ -635,7 +635,7 @@ CREATE TABLE "cc_webstream"
"description" VARCHAR(255) NOT NULL, "description" VARCHAR(255) NOT NULL,
"url" VARCHAR(255) NOT NULL, "url" VARCHAR(255) NOT NULL,
"length" interval default '00:00:00' NOT NULL, "length" interval default '00:00:00' NOT NULL,
"creator_id" VARCHAR(255) NOT NULL, "creator_id" INTEGER NOT NULL,
"mtime" TIMESTAMP(6) NOT NULL, "mtime" TIMESTAMP(6) NOT NULL,
"utime" TIMESTAMP(6) NOT NULL, "utime" TIMESTAMP(6) NOT NULL,
PRIMARY KEY ("id") PRIMARY KEY ("id")

View File

@ -543,6 +543,7 @@ var AIRTIME = (function(AIRTIME) {
.append('<option value="1">Files</option>') .append('<option value="1">Files</option>')
.append('<option value="2">Playlists</option>') .append('<option value="2">Playlists</option>')
.append('<option value="3">Smart Playlists</option>') .append('<option value="3">Smart Playlists</option>')
.append('<option value="4">Web Streams</option>')
.end() .end()
.change(function(ev){ .change(function(ev){
oTable.fnDraw(); oTable.fnDraw();
@ -613,12 +614,18 @@ var AIRTIME = (function(AIRTIME) {
callback = function() { callback = function() {
document.location.href = oItems.edit.url; document.location.href = oItems.edit.url;
}; };
} } else if (data.ftype === "playlist" || data.ftype === "block") {
else {
callback = function() { callback = function() {
//TODO var url = '/Playlist/edit';
AIRTIME.playlist.fnEdit(data.id, data.ftype); AIRTIME.playlist.fnEdit(data.id, data.ftype, url);
}; };
} else if (data.ftype === "stream") {
callback = function() {
var url = '/Webstream/edit';
AIRTIME.playlist.fnEdit(data.id, data.ftype, url);
}
} else {
throw new Exception("Unknown type: " + data.ftype);
} }
oItems.edit.callback = callback; oItems.edit.callback = callback;
} }

View File

@ -532,6 +532,7 @@ var AIRTIME = (function(AIRTIME){
//stream url //stream url
//default_length //default_length
//playlist name //playlist name
var id = $pl.find("#ws_id").attr("value");
var description = $pl.find("#description").val(); var description = $pl.find("#description").val();
var streamurl = $pl.find("#streamurl-element input").val(); var streamurl = $pl.find("#streamurl-element input").val();
var length = $pl.find("#streamlength-element input").val(); var length = $pl.find("#streamlength-element input").val();
@ -542,7 +543,7 @@ var AIRTIME = (function(AIRTIME){
var url = 'Webstream/save'; var url = 'Webstream/save';
$.post(url, $.post(url,
{format: "json", description: description, url:streamurl, length: length, name: name}, {format: "json", id:id, description: description, url:streamurl, length: length, name: name},
function(json){ function(json){
if (json.analysis){ if (json.analysis){
for (var s in json.analysis){ for (var s in json.analysis){
@ -730,8 +731,7 @@ var AIRTIME = (function(AIRTIME){
}); });
}; };
mod.fnEdit = function(id, type) { mod.fnEdit = function(id, type, url) {
var url = '/Playlist/edit';
stopAudioPreview(); stopAudioPreview();
@ -741,6 +741,7 @@ var AIRTIME = (function(AIRTIME){
openPlaylist(json); openPlaylist(json);
}); });
}; };
mod.fnDelete = function(plid) { mod.fnDelete = function(plid) {
var url, id, lastMod; var url, id, lastMod;

3
debian/control vendored
View File

@ -43,8 +43,7 @@ Depends: apache2,
unzip, unzip,
vorbis-tools, vorbis-tools,
zendframework | libzend-framework-php, zendframework | libzend-framework-php,
${misc:Depends}, ${misc:Depends}
${python:Depends}
Recommends: icecast2 Recommends: icecast2
Suggests: airtime-audio-samples, Suggests: airtime-audio-samples,
alsa-utils alsa-utils

6
debian/postinst vendored
View File

@ -12,7 +12,7 @@ includefile="${configdir}/apache.conf"
a2tplfile="${configdir}/apache.vhost.tpl" a2tplfile="${configdir}/apache.vhost.tpl"
phpinifile="${configdir}/airtime.ini" phpinifile="${configdir}/airtime.ini"
OLDVERSION="$2" OLDVERSION="$2"
NEWVERSION="2.1.4" NEWVERSION="2.2.0"
case "$1" in case "$1" in
configure|reconfigure) configure|reconfigure)
@ -218,10 +218,10 @@ case "$1" in
if [ "${OLDVERSION:0:5}" == "${NEWVERSION}" ] ; then if [ "${OLDVERSION:0:5}" == "${NEWVERSION}" ] ; then
echo "Reinstallation detected..." echo "Reinstallation detected..."
echo | ./airtime-install -rp 2> /var/log/airtime/reinstallation-errors.log echo | ./airtime-install --disable-deb-check -rp 2> /var/log/airtime/reinstallation-errors.log
else else
./airtime-install 2> /var/log/airtime/installation-errors.log ./airtime-install --disable-deb-check 2> /var/log/airtime/installation-errors.log
fi fi

2
debian/postrm vendored
View File

@ -103,7 +103,7 @@ case "$1" in
dpkg-statoverride --list $datadir &>/dev/null && \ dpkg-statoverride --list $datadir &>/dev/null && \
dpkg-statoverride --remove $datadir || true dpkg-statoverride --remove $datadir || true
# Only remove settings if purge is called as an argument # Only remove settings if purge is called as an argument
if [ "$1" = "purge" ]; then if [ "$1" = "purge" ]; then
echo "Removing configuration files from /etc/airtime/" >&2 echo "Removing configuration files from /etc/airtime/" >&2
rm -rf /etc/airtime || true rm -rf /etc/airtime || true

6
debian/prerm vendored
View File

@ -7,14 +7,10 @@ package_name="airtime"
datadir="/var/lib/${package_name}/tmp" datadir="/var/lib/${package_name}/tmp"
case "$1" in case "$1" in
remove) remove|purge)
cd $datadir/install_minimal/ && ./airtime-uninstall || true cd $datadir/install_minimal/ && ./airtime-uninstall || true
;; ;;
purge)
cd $datadir/install_minimal/ && ./airtime-uninstall --purge || true
;;
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;; ;;

View File

@ -34,31 +34,18 @@ rm airtime/airtime_mvc/library/phing/LICENSE
rm airtime/airtime_mvc/library/propel/LICENSE rm airtime/airtime_mvc/library/propel/LICENSE
rm airtime/airtime_mvc/library/soundcloud-api/README.md rm airtime/airtime_mvc/library/soundcloud-api/README.md
# Disable install script check for Debian package, it breaks the .deb install
sed -i '11s:DEB=$(dpkg:# DEB=$(dpkg:g' airtime/install_minimal/airtime-install
sed -i '13s\"$DEB" = "Status: install ok installed"\-f /var/lib/dpkg/info/airtime.config\g' airtime/install_minimal/airtime-install
sed -i '14s: Please use the debian package to upgrade.:..:g' airtime/install_minimal/airtime-install
sed -i '15s:exit 1:# We do not exit here:g' airtime/install_minimal/airtime-install
# Remove Liquidsoap binaries # Remove Liquidsoap binaries
rm -r airtime/python_apps/pypo/liquidsoap_bin/ rm -r airtime/python_apps/pypo/liquidsoap_bin/
# Disable installation of Liquidsoap binaries # Disable installation of Liquidsoap symlink
sed -i '84s:print:#print:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '84s:print:#print:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '86s:binary_path:#binary_path:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '86s:p = Popen:#p = Popen:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '88s:try:#try:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '87s:liq_path:#liq_path:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '89s:open:#open:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '89s:if p.returncode:#if p.returncode:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '91s:try:#try:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '90s:os.symlink:#os.symlink:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '92s:os.remove:#os.remove:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '91s:else:#else:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '93s:except:#except:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '92s:print:#print:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '95s:pass:#pass:g' airtime/python_apps/pypo/install/pypo-initialize.py sed -i '93s:sys.exit:#sys.exit:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '97s:os.symlink:#os.symlink:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '98s:except:#except:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '99s: """:""":g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '107s: """:""":g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '108s:print:#print:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '109s:print:#print:g' airtime/python_apps/pypo/install/pypo-initialize.py
sed -i '110s:sys.exit(1):#sys.exit(1):g' airtime/python_apps/pypo/install/pypo-initialize.py
#Remove phing library #Remove phing library
rm -r airtime/airtime_mvc/library/phing/ rm -r airtime/airtime_mvc/library/phing/
@ -73,7 +60,7 @@ rm -r airtime/install_full/
echo "running the build..." echo "running the build..."
debuild --no-lintian -b -uc -us $@ || exit debuild -b -uc -us $@ || exit
exit exit

View File

@ -8,7 +8,7 @@ exec 2>&1
if [ "$(id -u)" != "0" ]; then if [ "$(id -u)" != "0" ]; then
echo "Please run as root user." echo "Please run as root user."
exit 1 exit 1
fi fi
#Current dir #Current dir
@ -26,13 +26,23 @@ dist=`lsb_release -is`
if [ "$dist" = "Debian" ]; then if [ "$dist" = "Debian" ]; then
set +e set +e
grep "deb http://www.deb-multimedia.org squeeze main non-free" /etc/apt/sources.list grep -E "deb +http://www.deb-multimedia.org/? squeeze +main +non-free" /etc/apt/sources.list
returncode=$?
set -e set -e
if [ "$?" -ne "0" ]; then if [ "$returncode" -ne "0" ]; then
echo "deb http://www.deb-multimedia.org squeeze main non-free" >> /etc/apt/sources.list echo "deb http://www.deb-multimedia.org squeeze main non-free" >> /etc/apt/sources.list
fi fi
fi fi
codename=`lsb_release -sc`
set +e
grep -E "deb +http://apt.sourcefabric.org/? +$codename +main" /etc/apt/sources.list
returncode=$?
set -e
if [ "$returncode" != "0" ]; then
echo "deb http://apt.sourcefabric.org/ $codename main" >> /etc/apt/sources.list
fi
apt-get update apt-get update
# Updated package list # Updated package list
@ -57,6 +67,11 @@ else
apt-get -y install libzend-framework-php apt-get -y install libzend-framework-php
fi fi
#Install Sourcefabric's custom Liquidsoap debian package
apt-get -y --force-yes install sourcefabric-keyring
apt-get -y --force-yes install liquidsoap
# Apache Config File # Apache Config File
echo "----------------------------------------------------" echo "----------------------------------------------------"
echo "2. Apache Config File" echo "2. Apache Config File"
@ -68,7 +83,7 @@ if [ ! -f /etc/apache2/sites-available/airtime ]; then
a2enmod rewrite php5 a2enmod rewrite php5
service apache2 restart service apache2 restart
else else
echo "Apache config for Airtime already exists..." echo "Apache config for Airtime already exists..."
fi fi
# Enable Icecast # Enable Icecast

View File

@ -7,13 +7,6 @@ if [[ $EUID -ne 0 ]]; then
exit 1 exit 1
fi fi
set +e
DEB=$(dpkg -s airtime 2> /dev/null | grep Status)
set -e
if [[ "$DEB" = "Status: install ok installed" ]]; then
echo -e "\nDebian package of Airtime detected. Please use the debian package to upgrade.\n"
exit 1
fi
showhelp () { showhelp () {
echo "Usage: airtime-install [options] echo "Usage: airtime-install [options]
@ -37,8 +30,9 @@ pypo="f"
showrecorder="f" showrecorder="f"
web="f" web="f"
liquidsoap_keep_alive="f" liquidsoap_keep_alive="f"
disable_deb_check="f"
set -- $(getopt -l help,overwrite,preserve,no-db,reinstall,media-monitor,pypo,web,liquidsoap-keep-alive "hopnrmywl" "$@") set -- $(getopt -l help,overwrite,preserve,no-db,reinstall,media-monitor,pypo,web,liquidsoap-keep-alive,disable-deb-check "hopnrmywld" "$@")
while [ $# -gt 0 ] while [ $# -gt 0 ]
do do
case "$1" in case "$1" in
@ -51,6 +45,7 @@ do
(-y|--pypo) pypo="t";; (-y|--pypo) pypo="t";;
(-w|--web) web="t";; (-w|--web) web="t";;
(-l|--liquidsoap-keep-alive) liquidsoap_keep_alive="t";; (-l|--liquidsoap-keep-alive) liquidsoap_keep_alive="t";;
(-d|--disable-deb-check) disable_deb_check="t";;
(--) shift; break;; (--) shift; break;;
(-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
@ -67,6 +62,20 @@ if [ "$mediamonitor" = "f" -a "$pypo" = "f" -a "$web" = "f" ]; then
web="t" web="t"
fi fi
if [ "$disable_deb_check" == "f" ]; then
set +e
DEB=$(dpkg -s airtime 2> /dev/null | grep Status)
set -e
if [[ "$DEB" = "Status: install ok installed" ]]; then
echo -e "\nDebian package of Airtime detected. Please use the debian package to upgrade.\n"
exit 1
fi
fi
#Update apt sources.list to point to the new deb-multimedia domain.
sed -i s/www.debian-multimedia.org/www.deb-multimedia.org/g /etc/apt/sources.list
# Absolute path to this script, e.g. /home/user/bin/foo.sh # Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=`readlink -f $0` SCRIPT=`readlink -f $0`
# Absolute path this script is in, thus /home/user/bin # Absolute path this script is in, thus /home/user/bin

View File

@ -83,30 +83,13 @@ try:
print " * Installing Liquidsoap binary" print " * Installing Liquidsoap binary"
binary_path = os.path.join(PATH_LIQUIDSOAP_BIN, "liquidsoap_%s_%s" % (codename, arch)) p = Popen("which liquidsoap", shell=True, stdout=PIPE)
liq_path = p.communicate()[0].strip()
try: if p.returncode == 0:
open(binary_path) os.symlink(liq_path, "/usr/bin/airtime-liquidsoap")
else:
try: print " * Liquidsoap binary not found!"
os.remove("/usr/bin/airtime-liquidsoap")
except OSError, e:
#only get here if it doesn't exist
pass
os.symlink(binary_path, "/usr/bin/airtime-liquidsoap")
except IOError, e:
"""
shutil.copy can throw this exception for two reasons. First reason is that it cannot open the source file.
This is when the liquidsoap file we requested does not exist, and therefore tells the user we don't support
their OS/System architecture. The second reason for this exception is the shutil.copy cannot open the target file.
Since this script is being run as root (and we cannot install to a read-only device), this should never happen. So
it is safe to assume this exception is a result of the first case.
Note: We cannot simply use os.path.exists before this, since it sometimes gives us "false" incorrectly
"""
print "Unsupported OS/system architecture."
print e
sys.exit(1) sys.exit(1)
#initialize init.d scripts #initialize init.d scripts

View File

@ -3,6 +3,11 @@ def notify(m)
system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --data='#{!pypo_data}' --media-id=#{m['schedule_table_id']} &") system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --data='#{!pypo_data}' --media-id=#{m['schedule_table_id']} &")
end end
def notify_stream(m)
log("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --stream --uri=#{base64.encode(m['uri'])} --title=#{base64.encode(m['title'])} &")
#system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --stream --uri=#{base64.encode(m['uri'])} --title=#{base64.encode(m['title'])} &")
end
# A function applied to each metadata chunk # A function applied to each metadata chunk
def append_title(m) = def append_title(m) =
log("Using stream_format #{!stream_metadata_type}") log("Using stream_format #{!stream_metadata_type}")
@ -86,11 +91,11 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
fallible = true, fallible = true,
url = url, url = url,
description = description, description = description,
name = name,
genre = genre, genre = genre,
user = !user_ref, user = !user_ref,
on_error = on_error, on_error = on_error,
on_connect = on_connect, on_connect = on_connect)
name = name)
if type == "mp3" then if type == "mp3" then
if bitrate == 24 then if bitrate == 24 then
ignore(output(%mp3(bitrate = 24),s)) ignore(output(%mp3(bitrate = 24),s))

View File

@ -20,7 +20,6 @@ queue = amplify(1., override="replay_gain", queue)
set("harbor.bind_addr", "0.0.0.0") set("harbor.bind_addr", "0.0.0.0")
#TODO: Need to create a randomized password for every instance #TODO: Need to create a randomized password for every instance
web_stream = input.harbor("test-harbor",port=8999,password="hackme")
current_dyn_id = ref '' current_dyn_id = ref ''
pypo_data = ref '0' pypo_data = ref '0'
@ -39,6 +38,9 @@ just_switched = ref false
%include "ls_lib.liq" %include "ls_lib.liq"
web_stream = input.harbor("test-harbor",port=8999,password="hackme")
web_stream = on_metadata(notify_stream, web_stream)
queue = on_metadata(notify, queue) queue = on_metadata(notify, queue)
queue = map_metadata(append_title, queue) queue = map_metadata(append_title, queue)
# the crossfade function controls fade in/out # the crossfade function controls fade in/out
@ -270,7 +272,7 @@ if s1_enable == true then
s1_namespace := s1_mount s1_namespace := s1_mount
end end
server.register(namespace=!s1_namespace, "connected", fun (s) -> begin !s1_connected end) server.register(namespace=!s1_namespace, "connected", fun (s) -> begin !s1_connected end)
output_to(s1_output, s1_type, s1_bitrate, s1_host, s1_port, s1_pass, s1_mount, s1_url, s1_description, s1_genre, s1_user, s, "1", s1_connected, s1_name) output_to(s1_output, s1_type, s1_bitrate, s1_host, s1_port, s1_pass, s1_mount, s1_url, s1_description, s1_genre, s1_user, s, "1", s1_connected, s1_description)
end end
if s2_enable == true then if s2_enable == true then
@ -280,7 +282,7 @@ if s2_enable == true then
s2_namespace := s2_mount s2_namespace := s2_mount
end end
server.register(namespace=!s2_namespace, "connected", fun (s) -> begin !s2_connected end) server.register(namespace=!s2_namespace, "connected", fun (s) -> begin !s2_connected end)
output_to(s2_output, s2_type, s2_bitrate, s2_host, s2_port, s2_pass, s2_mount, s2_url, s2_description, s2_genre, s2_user, s, "2", s2_connected, s2_name) output_to(s2_output, s2_type, s2_bitrate, s2_host, s2_port, s2_pass, s2_mount, s2_url, s2_description, s2_genre, s2_user, s, "2", s2_connected, s2_description)
end end
@ -291,7 +293,7 @@ if s3_enable == true then
s3_namespace := s3_mount s3_namespace := s3_mount
end end
server.register(namespace=!s3_namespace, "connected", fun (s) -> begin !s3_connected end) server.register(namespace=!s3_namespace, "connected", fun (s) -> begin !s3_connected end)
output_to(s3_output, s3_type, s3_bitrate, s3_host, s3_port, s3_pass, s3_mount, s3_url, s3_description, s3_genre, s3_user, s, "3", s3_connected, s3_name) output_to(s3_output, s3_type, s3_bitrate, s3_host, s3_port, s3_pass, s3_mount, s3_url, s3_description, s3_genre, s3_user, s, "3", s3_connected, s3_description)
end end
ignore(output.dummy(blank())) ignore(output.dummy(blank()))