Merge branch 'saas' into saas-embed-player
This commit is contained in:
commit
5a373ac604
|
@ -37,7 +37,7 @@ require_once (APPLICATION_PATH."/logging/Logging.php");
|
||||||
Logging::setLogPath('/var/log/airtime/zendphp.log');
|
Logging::setLogPath('/var/log/airtime/zendphp.log');
|
||||||
|
|
||||||
// We need to manually route because we can't load Zend without the database being initialized first.
|
// We need to manually route because we can't load Zend without the database being initialized first.
|
||||||
if (array_key_exists("REQUEST_URI", $_SERVER) && (strpos($_SERVER["REQUEST_URI"], "/provisioning/create") !== false)) {
|
if (array_key_exists("REQUEST_URI", $_SERVER) && (stripos($_SERVER["REQUEST_URI"], "/provisioning/create") !== false)) {
|
||||||
$provisioningHelper = new ProvisioningHelper($CC_CONFIG["apiKey"][0]);
|
$provisioningHelper = new ProvisioningHelper($CC_CONFIG["apiKey"][0]);
|
||||||
$provisioningHelper->createAction();
|
$provisioningHelper->createAction();
|
||||||
die();
|
die();
|
||||||
|
@ -52,6 +52,7 @@ Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
||||||
|
|
||||||
$front = Zend_Controller_Front::getInstance();
|
$front = Zend_Controller_Front::getInstance();
|
||||||
$front->registerPlugin(new RabbitMqPlugin());
|
$front->registerPlugin(new RabbitMqPlugin());
|
||||||
|
$front->throwExceptions(false);
|
||||||
|
|
||||||
//localization configuration
|
//localization configuration
|
||||||
Application_Model_Locale::configureLocalization();
|
Application_Model_Locale::configureLocalization();
|
||||||
|
|
|
@ -53,14 +53,30 @@ class Amazon_S3StorageBackend extends StorageBackend
|
||||||
// Records in the database will remain in case we have to restore the files.
|
// Records in the database will remain in case we have to restore the files.
|
||||||
public function deleteAllCloudFileObjects()
|
public function deleteAllCloudFileObjects()
|
||||||
{
|
{
|
||||||
$this->s3Client->deleteMatchingObjects(
|
$bucket = $this->getBucket();
|
||||||
$bucket = $this->getBucket(),
|
$prefix = $this->getFilePrefix();
|
||||||
$prefix = $this->getFilePrefix());
|
|
||||||
|
//Add a trailing slash in for safety
|
||||||
|
//(so that deleting /13/413 doesn't delete /13/41313 !)
|
||||||
|
$prefix = $prefix . "/";
|
||||||
|
|
||||||
|
//Do a bunch of safety checks to ensure we don't delete more than we intended.
|
||||||
|
//An valid prefix is like "12/4312" for instance 4312.
|
||||||
|
$slashPos = strpos($prefix, "/");
|
||||||
|
if (($slashPos === FALSE) || //Slash must exist
|
||||||
|
($slashPos != 2) || //Slash must be the third character
|
||||||
|
(strlen($prefix) <= $slashPos) || //String must have something after the first slash
|
||||||
|
(substr_count($prefix, "/") != 2)) //String must have two slashes
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid file prefix in " . __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
$this->s3Client->deleteMatchingObjects($bucket, $prefix);
|
||||||
|
}
|
||||||
|
|
||||||
public function getFilePrefix()
|
public function getFilePrefix()
|
||||||
{
|
{
|
||||||
$hostingId = Billing::getClientInstanceId();
|
$hostingId = Billing::getClientInstanceId();
|
||||||
return substr($hostingId, -2)."/".$hostingId;
|
$filePrefix = substr($hostingId, -2)."/".$hostingId;
|
||||||
|
return $filePrefix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ class ProvisioningHelper
|
||||||
// Parameter values
|
// Parameter values
|
||||||
private $dbuser, $dbpass, $dbname, $dbhost, $dbowner, $apikey;
|
private $dbuser, $dbpass, $dbname, $dbhost, $dbowner, $apikey;
|
||||||
private $instanceId;
|
private $instanceId;
|
||||||
|
private $station_name, $description;
|
||||||
|
|
||||||
public function __construct($apikey)
|
public function __construct($apikey)
|
||||||
{
|
{
|
||||||
|
@ -34,34 +35,37 @@ class ProvisioningHelper
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$this->parsePostParams();
|
$this->parsePostParams();
|
||||||
|
|
||||||
//For security, the Airtime Pro provisioning system creates the database for the user.
|
//For security, the Airtime Pro provisioning system creates the database for the user.
|
||||||
$this->setNewDatabaseConnection();
|
if ($this->dbhost && !empty($this->dbhost)) {
|
||||||
|
$this->setNewDatabaseConnection();
|
||||||
|
|
||||||
//if ($this->checkDatabaseExists()) {
|
//if ($this->checkDatabaseExists()) {
|
||||||
// throw new Exception("ERROR: Airtime database already exists");
|
// throw new Exception("ERROR: Airtime database already exists");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (!$this->checkDatabaseExists()) {
|
if (!$this->checkDatabaseExists()) {
|
||||||
throw new Exception("ERROR: $this->dbname database does not exist.");
|
throw new Exception("ERROR: $this->dbname database does not exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//We really want to do this check because all the Propel-generated SQL starts with "DROP TABLE IF EXISTS".
|
//We really want to do this check because all the Propel-generated SQL starts with "DROP TABLE IF EXISTS".
|
||||||
//If we don't check, then a second call to this API endpoint would wipe all the tables!
|
//If we don't check, then a second call to this API endpoint would wipe all the tables!
|
||||||
if ($this->checkTablesExist()) {
|
if ($this->checkTablesExist()) {
|
||||||
throw new Exception("ERROR: airtime tables already exists");
|
throw new Exception("ERROR: airtime tables already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->createDatabaseTables();
|
||||||
|
$this->initializeMusicDirsTable($this->instanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$this->createDatabase();
|
//$this->createDatabase();
|
||||||
|
|
||||||
//All we need to do is create the database tables.
|
//All we need to do is create the database tables.
|
||||||
|
|
||||||
$this->createDatabaseTables();
|
$this->initializePrefs();
|
||||||
$this->initializeMusicDirsTable($this->instanceId);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
Logging::error($e->getMessage()
|
Logging::error($e->getMessage());
|
||||||
);
|
|
||||||
echo $e->getMessage() . PHP_EOL;
|
echo $e->getMessage() . PHP_EOL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -94,6 +98,7 @@ class ProvisioningHelper
|
||||||
// Result is either boolean FALSE (no table found) or PDOStatement Object (table found)
|
// Result is either boolean FALSE (no table found) or PDOStatement Object (table found)
|
||||||
return $result !== FALSE;
|
return $result !== FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parsePostParams()
|
private function parsePostParams()
|
||||||
{
|
{
|
||||||
$this->dbuser = $_POST['dbuser'];
|
$this->dbuser = $_POST['dbuser'];
|
||||||
|
@ -102,6 +107,9 @@ class ProvisioningHelper
|
||||||
$this->dbhost = $_POST['dbhost'];
|
$this->dbhost = $_POST['dbhost'];
|
||||||
$this->dbowner = $_POST['dbowner'];
|
$this->dbowner = $_POST['dbowner'];
|
||||||
$this->instanceId = $_POST['instanceid'];
|
$this->instanceId = $_POST['instanceid'];
|
||||||
|
|
||||||
|
$this->station_name = $_POST['station_name'];
|
||||||
|
$this->description = $_POST['description'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,9 +119,9 @@ class ProvisioningHelper
|
||||||
private function setNewDatabaseConnection()
|
private function setNewDatabaseConnection()
|
||||||
{
|
{
|
||||||
self::$dbh = new PDO("pgsql:host=" . $this->dbhost
|
self::$dbh = new PDO("pgsql:host=" . $this->dbhost
|
||||||
. ";dbname=" . $this->dbname
|
. ";dbname=" . $this->dbname
|
||||||
. ";port=5432" . ";user=" . $this->dbuser
|
. ";port=5432" . ";user=" . $this->dbuser
|
||||||
. ";password=" . $this->dbpass);
|
. ";password=" . $this->dbpass);
|
||||||
//Turn on PDO exceptions because they're off by default.
|
//Turn on PDO exceptions because they're off by default.
|
||||||
//self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
//self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
$err = self::$dbh->errorInfo();
|
$err = self::$dbh->errorInfo();
|
||||||
|
@ -130,8 +138,8 @@ class ProvisioningHelper
|
||||||
{
|
{
|
||||||
Logging::info("Creating database...");
|
Logging::info("Creating database...");
|
||||||
$statement = self::$dbh->prepare("CREATE DATABASE " . pg_escape_string($this->dbname)
|
$statement = self::$dbh->prepare("CREATE DATABASE " . pg_escape_string($this->dbname)
|
||||||
. " WITH ENCODING 'UTF8' TEMPLATE template0"
|
. " WITH ENCODING 'UTF8' TEMPLATE template0"
|
||||||
. " OWNER " . pg_escape_string($this->dbowner));
|
. " OWNER " . pg_escape_string($this->dbowner));
|
||||||
if (!$statement->execute()) {
|
if (!$statement->execute()) {
|
||||||
throw new Exception("ERROR: Failed to create Airtime database");
|
throw new Exception("ERROR: Failed to create Airtime database");
|
||||||
}
|
}
|
||||||
|
@ -182,5 +190,16 @@ class ProvisioningHelper
|
||||||
$musicDir->save();
|
$musicDir->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize preference values passed from the dashboard (if any exist)
|
||||||
|
*/
|
||||||
|
private function initializePrefs() {
|
||||||
|
if ($this->station_name) {
|
||||||
|
Application_Model_Preference::SetStationName($this->station_name);
|
||||||
|
}
|
||||||
|
if ($this->description) {
|
||||||
|
Application_Model_Preference::SetStationDescription($this->description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,40 @@
|
||||||
<?php
|
<?php
|
||||||
|
class ErrorController extends Zend_Controller_Action {
|
||||||
|
|
||||||
class ErrorController extends Zend_Controller_Action
|
public function init()
|
||||||
{
|
|
||||||
|
|
||||||
public function errorAction()
|
|
||||||
{
|
{
|
||||||
|
//The default layout includes the Dashboard header, which may contain private information.
|
||||||
|
//We cannot show that.
|
||||||
|
$this->view->layout()->disableLayout();
|
||||||
|
$this->setupCSS();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorAction() {
|
||||||
$errors = $this->_getParam('error_handler');
|
$errors = $this->_getParam('error_handler');
|
||||||
|
|
||||||
switch ($errors->type) {
|
if ($errors) {
|
||||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
|
// log error message and stack trace
|
||||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
|
Logging::error($errors->exception->getMessage());
|
||||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
|
Logging::error($errors->exception->getTraceAsString());
|
||||||
|
|
||||||
// 404 error -- controller or action not found
|
switch ($errors->type) {
|
||||||
$this->getResponse()->setHttpResponseCode(404);
|
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE :
|
||||||
$this->view->message = _('Page not found');
|
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER :
|
||||||
break;
|
$this->error404Action();
|
||||||
default:
|
break;
|
||||||
// application error
|
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION :
|
||||||
$this->getResponse()->setHttpResponseCode(500);
|
$this->error400Action();
|
||||||
$this->view->message = _('Application error');
|
break;
|
||||||
break;
|
default :
|
||||||
|
$this->error500Action();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$exceptions = $this->_getAllParams();
|
||||||
|
Logging::error($exceptions);
|
||||||
|
$this->error500Action();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log exception, if logger available
|
// Log exception, if logger available
|
||||||
|
@ -33,11 +47,17 @@ class ErrorController extends Zend_Controller_Action
|
||||||
$this->view->exception = $errors->exception;
|
$this->view->exception = $errors->exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->view->request = $errors->request;
|
$this->view->request = $errors->request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLog()
|
private function setupCSS()
|
||||||
{
|
{
|
||||||
|
$CC_CONFIG = Config::getConfig();
|
||||||
|
$staticBaseDir = Application_Common_OsPath::formatDirectoryWithDirectorySeparators($CC_CONFIG['staticBaseDir']);
|
||||||
|
$this->view->headLink()->appendStylesheet($staticBaseDir . 'css/styles.css?' . $CC_CONFIG['airtime_version']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLog() {
|
||||||
$bootstrap = $this->getInvokeArg('bootstrap');
|
$bootstrap = $this->getInvokeArg('bootstrap');
|
||||||
if (!$bootstrap->hasPluginResource('Log')) {
|
if (!$bootstrap->hasPluginResource('Log')) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -47,9 +67,43 @@ class ErrorController extends Zend_Controller_Action
|
||||||
return $log;
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deniedAction()
|
/**
|
||||||
{
|
* 404 error - route or controller
|
||||||
// action body
|
*/
|
||||||
|
public function error404Action() {
|
||||||
|
$this->_helper->viewRenderer('error-404');
|
||||||
|
$this->getResponse()->setHttpResponseCode(404);
|
||||||
|
$this->view->message = _('Page not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 400 error - no such action
|
||||||
|
*/
|
||||||
|
public function error400Action() {
|
||||||
|
$this->_helper->viewRenderer('error-400');
|
||||||
|
$this->getResponse()->setHttpResponseCode(400);
|
||||||
|
$this->view->message = _('The requested action is not supported.');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 403 error - permission denied
|
||||||
|
*/
|
||||||
|
public function error403Action() {
|
||||||
|
|
||||||
|
$this->_helper->viewRenderer('error-403');
|
||||||
|
$this->getResponse()->setHttpResponseCode(403);
|
||||||
|
$this->view->message = _('You do not have permission to access this resource.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 500 error - internal server error
|
||||||
|
*/
|
||||||
|
public function error500Action() {
|
||||||
|
|
||||||
|
$this->_helper->viewRenderer('error-500');
|
||||||
|
|
||||||
|
$this->getResponse()->setHttpResponseCode(500);
|
||||||
|
$this->view->message = _('An internal application error has occurred.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,40 @@ class ProvisioningController extends Zend_Controller_Action
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint to change Airtime preferences remotely.
|
||||||
|
* Mainly for use with the dashboard right now.
|
||||||
|
*/
|
||||||
|
public function changeAction() {
|
||||||
|
$this->view->layout()->disableLayout();
|
||||||
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
|
if (!RestAuth::verifyAuth(true, false, $this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// This is hacky and should be genericized
|
||||||
|
if ($_POST['station_name']) {
|
||||||
|
Application_Model_Preference::SetStationName($_POST['station_name']);
|
||||||
|
}
|
||||||
|
if ($_POST['description']) {
|
||||||
|
Application_Model_Preference::SetStationDescription($_POST['description']);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->getResponse()
|
||||||
|
->setHttpResponseCode(400)
|
||||||
|
->appendBody("ERROR: " . $e->getMessage());
|
||||||
|
Logging::error($e->getMessage());
|
||||||
|
echo $e->getMessage() . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getResponse()
|
||||||
|
->setHttpResponseCode(200)
|
||||||
|
->appendBody("OK");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the Airtime Pro station's files from Amazon S3
|
* Delete the Airtime Pro station's files from Amazon S3
|
||||||
*/
|
*/
|
||||||
|
@ -31,12 +65,12 @@ class ProvisioningController extends Zend_Controller_Action
|
||||||
}
|
}
|
||||||
|
|
||||||
$CC_CONFIG = Config::getConfig();
|
$CC_CONFIG = Config::getConfig();
|
||||||
|
|
||||||
foreach ($CC_CONFIG["supportedStorageBackends"] as $storageBackend) {
|
foreach ($CC_CONFIG["supportedStorageBackends"] as $storageBackend) {
|
||||||
$proxyStorageBackend = new ProxyStorageBackend($storageBackend);
|
$proxyStorageBackend = new ProxyStorageBackend($storageBackend);
|
||||||
$proxyStorageBackend->deleteAllCloudFileObjects();
|
$proxyStorageBackend->deleteAllCloudFileObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getResponse()
|
$this->getResponse()
|
||||||
->setHttpResponseCode(200)
|
->setHttpResponseCode(200)
|
||||||
->appendBody("OK");
|
->appendBody("OK");
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
||||||
{
|
{
|
||||||
$this->_errorPage = array('module' => 'default',
|
$this->_errorPage = array('module' => 'default',
|
||||||
'controller' => 'error',
|
'controller' => 'error',
|
||||||
'action' => 'denied');
|
'action' => 'error');
|
||||||
|
|
||||||
$this->_roleName = $roleName;
|
$this->_roleName = $roleName;
|
||||||
|
|
||||||
|
@ -111,7 +111,16 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
||||||
$controller = strtolower($request->getControllerName());
|
$controller = strtolower($request->getControllerName());
|
||||||
Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
||||||
|
|
||||||
if (in_array($controller, array("api", "auth", "locale", "upgrade", 'whmcs-login', "provisioning"))) {
|
if (in_array($controller, array(
|
||||||
|
"api",
|
||||||
|
"auth",
|
||||||
|
"error",
|
||||||
|
"locale",
|
||||||
|
"upgrade",
|
||||||
|
'whmcs-login',
|
||||||
|
"provisioning"
|
||||||
|
)))
|
||||||
|
{
|
||||||
$this->setRoleName("G");
|
$this->setRoleName("G");
|
||||||
} elseif (!Zend_Auth::getInstance()->hasIdentity()) {
|
} elseif (!Zend_Auth::getInstance()->hasIdentity()) {
|
||||||
|
|
||||||
|
|
|
@ -326,6 +326,11 @@ class Application_Model_Preference
|
||||||
return self::getValue("station_name");
|
return self::getValue("station_name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function SetStationName($station_name)
|
||||||
|
{
|
||||||
|
self::setValue("station_name", $station_name);
|
||||||
|
}
|
||||||
|
|
||||||
public static function SetAutoUploadRecordedShowToSoundcloud($upload)
|
public static function SetAutoUploadRecordedShowToSoundcloud($upload)
|
||||||
{
|
{
|
||||||
self::setValue("soundcloud_auto_upload_recorded_show", $upload);
|
self::setValue("soundcloud_auto_upload_recorded_show", $upload);
|
||||||
|
|
|
@ -381,4 +381,7 @@ class AirtimeUpgrader2511 extends AirtimeUpgrader
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function downgrade() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN";
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title><?php echo _("An error has occurred.") ?></title>
|
||||||
|
<?php echo $this->headLink(); ?>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="error-content" id="error-400">
|
||||||
|
<h2><?php echo _("Bad Request!")?></h2>
|
||||||
|
<p><?php echo _("The requested action is not supported!")?></p>
|
||||||
|
<div class="button-bar">
|
||||||
|
<a class="toggle-button" href="<?php echo $this->baseUrl('dashboard/help'); ?>"><?php echo _("Help") ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN";
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title><?php echo _("An error has occurred.") ?></title>
|
||||||
|
<?php echo $this->headLink(); ?>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="error-content" id="error-403">
|
||||||
|
<h2><?php echo _("Access Denied!")?></h2>
|
||||||
|
<p><?php echo _("You do not have permission to access this page!")?></p>
|
||||||
|
<div class="button-bar">
|
||||||
|
<a class="toggle-button" href="<?php echo $this->baseUrl('dashboard/help'); ?>"><?php echo _("Help") ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN";
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title><?php echo _("An error has occurred.") ?></title>
|
||||||
|
<?php echo $this->headLink(); ?>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="error-content" id="error-500">
|
||||||
|
<h2><?php echo _("Oops!")?></h2>
|
||||||
|
<p><?php echo _("Something went wrong!")?></p>
|
||||||
|
<div class="button-bar">
|
||||||
|
<a class="toggle-button" href="<?php echo $this->baseUrl('dashboard/help'); ?>"><?php echo _("Help") ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -3,7 +3,8 @@
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title><?php echo _("Zend Framework Default Application") ?></title>
|
<title><?php echo _("An error has occurred.") ?></title>
|
||||||
|
<?php echo $this->headLink(); ?>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="error-content">
|
<div class="error-content">
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -899,20 +899,19 @@ input[type="checkbox"] {
|
||||||
|
|
||||||
/* Remove any visible csrf form token footprint */
|
/* Remove any visible csrf form token footprint */
|
||||||
#csrf-label {
|
#csrf-label {
|
||||||
height: 0;
|
display: none;
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#csrf-element {
|
#csrf-element {
|
||||||
height: 8px;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#csrf-label .errors li, #csrf-element .errors li {
|
#csrf-label .errors li, #csrf-element .errors li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
.login_box {
|
.login_box {
|
||||||
margin: 0 auto 0 auto;
|
margin: 0 auto 0 auto;
|
||||||
|
@ -1031,7 +1030,6 @@ input[type="checkbox"] {
|
||||||
#pref_form p.description {
|
#pref_form p.description {
|
||||||
color: #3b3b3b;
|
color: #3b3b3b;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dt.block-display, dd.block-display {
|
dt.block-display, dd.block-display {
|
||||||
|
@ -2193,7 +2191,7 @@ dd.radio-inline-list, .preferences dd.radio-inline-list, .stream-config dd.radio
|
||||||
width: 98.5%;
|
width: 98.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences dd#SoundCloudTags-element.block-display .input_text_area {
|
.preferences dd.block-display .input_text_area {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2202,14 +2200,10 @@ dd.radio-inline-list, .preferences dd.radio-inline-list, .stream-config dd.radio
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences #logo-remove-btn {
|
.preferences #logo-remove-btn {
|
||||||
float: right;
|
/*float: left;*/
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences #Logo-img-container {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#show_time_info {
|
#show_time_info {
|
||||||
font-size:12px;
|
font-size:12px;
|
||||||
height:30px;
|
height:30px;
|
||||||
|
@ -2570,19 +2564,21 @@ dt.block-display.info-block {
|
||||||
|
|
||||||
/*---//////////////////// ERROR PAGE ////////////////////---*/
|
/*---//////////////////// ERROR PAGE ////////////////////---*/
|
||||||
|
|
||||||
.error-content {
|
.error-content {
|
||||||
background:url(images/404.png) no-repeat 0 0;
|
background:url(images/maintenance.png) no-repeat 0 0;
|
||||||
width:300px;
|
width:360px;
|
||||||
margin: 24px 15px;
|
height:350px;
|
||||||
padding: 0px 10px 0 420px;
|
margin:auto;
|
||||||
|
margin-top:25px;
|
||||||
|
padding:auto;
|
||||||
}
|
}
|
||||||
.error-content h2 {
|
.error-content h2 {
|
||||||
margin:0;
|
margin:0;
|
||||||
padding:0 0 10px 0;
|
padding:350px 0 10px 0;
|
||||||
font-size:36px;
|
font-size:36px;
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
color:#3e3e3e;
|
color:#3e3e3e;
|
||||||
text-align:left;
|
text-align:center;
|
||||||
letter-spacing:-.3px;
|
letter-spacing:-.3px;
|
||||||
text-shadow: rgba(248,248,248,.3) 0 1px 0, rgba(0,0,0,.8) 0 -1px 0;
|
text-shadow: rgba(248,248,248,.3) 0 1px 0, rgba(0,0,0,.8) 0 -1px 0;
|
||||||
rgba(51,51,51,.9)
|
rgba(51,51,51,.9)
|
||||||
|
@ -2590,12 +2586,14 @@ dt.block-display.info-block {
|
||||||
.error-content p {
|
.error-content p {
|
||||||
color: #272727;
|
color: #272727;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align:center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding:8px 2px;
|
padding:8px 2px;
|
||||||
}
|
}
|
||||||
.error-content .button-bar {
|
.error-content .button-bar {
|
||||||
margin-top:47px;
|
margin-top:47px;
|
||||||
padding-left:2px;
|
padding-left:2px;
|
||||||
|
text-align:center;
|
||||||
}
|
}
|
||||||
.error-content .toggle-button {
|
.error-content .toggle-button {
|
||||||
border: 1px solid #434343;
|
border: 1px solid #434343;
|
||||||
|
@ -3142,3 +3140,4 @@ dd .stream-status {
|
||||||
}
|
}
|
||||||
.quota-reached {
|
.quota-reached {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
import Queue
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
from metadata_analyzer import MetadataAnalyzer
|
from metadata_analyzer import MetadataAnalyzer
|
||||||
from filemover_analyzer import FileMoverAnalyzer
|
from filemover_analyzer import FileMoverAnalyzer
|
||||||
|
@ -45,8 +46,8 @@ class AnalyzerPipeline:
|
||||||
AnalyzerPipeline.python_logger_deadlock_workaround()
|
AnalyzerPipeline.python_logger_deadlock_workaround()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not isinstance(queue, multiprocessing.queues.Queue):
|
if not isinstance(queue, Queue.Queue):
|
||||||
raise TypeError("queue must be a multiprocessing.Queue()")
|
raise TypeError("queue must be a Queue.Queue()")
|
||||||
if not isinstance(audio_file_path, unicode):
|
if not isinstance(audio_file_path, unicode):
|
||||||
raise TypeError("audio_file_path must be unicode. Was of type " + type(audio_file_path).__name__ + " instead.")
|
raise TypeError("audio_file_path must be unicode. Was of type " + type(audio_file_path).__name__ + " instead.")
|
||||||
if not isinstance(import_directory, unicode):
|
if not isinstance(import_directory, unicode):
|
||||||
|
|
|
@ -6,6 +6,7 @@ import select
|
||||||
import signal
|
import signal
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
import Queue
|
||||||
from analyzer_pipeline import AnalyzerPipeline
|
from analyzer_pipeline import AnalyzerPipeline
|
||||||
from status_reporter import StatusReporter
|
from status_reporter import StatusReporter
|
||||||
from cloud_storage_uploader import CloudStorageUploader
|
from cloud_storage_uploader import CloudStorageUploader
|
||||||
|
@ -212,6 +213,7 @@ class MessageListener:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def spawn_analyzer_process(audio_file_path, import_directory, original_filename, storage_backend, file_prefix, cloud_storage_config):
|
def spawn_analyzer_process(audio_file_path, import_directory, original_filename, storage_backend, file_prefix, cloud_storage_config):
|
||||||
''' Spawn a child process to analyze and import a new audio file. '''
|
''' Spawn a child process to analyze and import a new audio file. '''
|
||||||
|
'''
|
||||||
q = multiprocessing.Queue()
|
q = multiprocessing.Queue()
|
||||||
p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis,
|
p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis,
|
||||||
args=(q, audio_file_path, import_directory, original_filename, storage_backend, file_prefix, cloud_storage_config))
|
args=(q, audio_file_path, import_directory, original_filename, storage_backend, file_prefix, cloud_storage_config))
|
||||||
|
@ -223,7 +225,16 @@ class MessageListener:
|
||||||
logging.info(results)
|
logging.info(results)
|
||||||
else:
|
else:
|
||||||
raise Exception("Analyzer process terminated unexpectedly.")
|
raise Exception("Analyzer process terminated unexpectedly.")
|
||||||
|
'''
|
||||||
|
|
||||||
|
q = Queue.Queue()
|
||||||
|
try:
|
||||||
|
AnalyzerPipeline.run_analysis(q, audio_file_path, import_directory, original_filename, storage_backend, file_prefix, cloud_storage_config)
|
||||||
|
results = q.get()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Analyzer pipeline exception", e)
|
||||||
|
pass
|
||||||
|
|
||||||
# Ensure our queue doesn't fill up and block due to unexpected behaviour. Defensive code.
|
# Ensure our queue doesn't fill up and block due to unexpected behaviour. Defensive code.
|
||||||
while not q.empty():
|
while not q.empty():
|
||||||
q.get()
|
q.get()
|
||||||
|
|
|
@ -20,10 +20,15 @@ def create_liquidsoap_annotation(media):
|
||||||
# with the metadata we get from Airtime. (You can modify metadata in Airtime's library,
|
# with the metadata we get from Airtime. (You can modify metadata in Airtime's library,
|
||||||
# which doesn't get saved back to the file.)
|
# which doesn't get saved back to the file.)
|
||||||
if 'metadata' in media:
|
if 'metadata' in media:
|
||||||
|
|
||||||
if 'artist_name' in media['metadata']:
|
if 'artist_name' in media['metadata']:
|
||||||
annotation += ',artist="%s"' % (media['metadata']['artist_name'])
|
artist_name = media['metadata']['artist_name']
|
||||||
|
if isinstance(artist_name, str):
|
||||||
|
annotation += ',artist="%s"' % (artist_name.replace('"', '\\"'))
|
||||||
if 'track_title' in media['metadata']:
|
if 'track_title' in media['metadata']:
|
||||||
annotation += ',title="%s"' % (media['metadata']['track_title'])
|
track_title = media['metadata']['track_title']
|
||||||
|
if isinstance(track_title, str):
|
||||||
|
annotation += ',title="%s"' % (track_title.replace('"', '\\"'))
|
||||||
|
|
||||||
annotation += ":" + filename
|
annotation += ":" + filename
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue