Merge branch 'saas-dev' into saas-landing-page
Conflicts: airtime_mvc/application/controllers/ApiController.php airtime_mvc/application/views/scripts/embed/player.phtml
This commit is contained in:
commit
8f8b0b7f4d
46 changed files with 1033 additions and 348 deletions
|
@ -101,6 +101,11 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
|
||||||
$csrf_namespace->authtoken = sha1(uniqid(rand(), 1));
|
$csrf_namespace->authtoken = sha1(uniqid(rand(), 1));
|
||||||
$csrf_namespace->setExpirationSeconds(2 * 60 * 60);
|
$csrf_namespace->setExpirationSeconds(2 * 60 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Here we are closing the session for writing because otherwise no requests
|
||||||
|
//in this session will be handled in parallel. This gives a major boost to the perceived performance
|
||||||
|
//of the application (page load times are more consistent, no lock contention).
|
||||||
|
session_write_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +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;
|
private $stationName, $description;
|
||||||
|
|
||||||
public function __construct($apikey)
|
public function __construct($apikey)
|
||||||
{
|
{
|
||||||
|
@ -40,18 +40,14 @@ class ProvisioningHelper
|
||||||
if ($this->dbhost && !empty($this->dbhost)) {
|
if ($this->dbhost && !empty($this->dbhost)) {
|
||||||
$this->setNewDatabaseConnection();
|
$this->setNewDatabaseConnection();
|
||||||
|
|
||||||
//if ($this->checkDatabaseExists()) {
|
|
||||||
// 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 DatabaseDoesNotExistException("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 DatabaseAlreadyExistsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->createDatabaseTables();
|
$this->createDatabaseTables();
|
||||||
|
@ -63,11 +59,19 @@ class ProvisioningHelper
|
||||||
//All we need to do is create the database tables.
|
//All we need to do is create the database tables.
|
||||||
|
|
||||||
$this->initializePrefs();
|
$this->initializePrefs();
|
||||||
} catch (Exception $e) {
|
} catch (DatabaseDoesNotExistException $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;
|
||||||
|
} catch (DatabaseAlreadyExistsException $e) {
|
||||||
|
// When we recreate a terminated instance, the process will fail
|
||||||
|
// if we return a 40x response here. In order to circumvent this,
|
||||||
|
// just return a 200; we still avoid dropping the existing tables
|
||||||
|
http_response_code(200);
|
||||||
|
Logging::info($e->getMessage());
|
||||||
|
echo $e->getMessage() . PHP_EOL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
|
@ -108,7 +112,7 @@ class ProvisioningHelper
|
||||||
$this->dbowner = $_POST['dbowner'];
|
$this->dbowner = $_POST['dbowner'];
|
||||||
$this->instanceId = $_POST['instanceid'];
|
$this->instanceId = $_POST['instanceid'];
|
||||||
|
|
||||||
$this->station_name = $_POST['station_name'];
|
$this->stationName = $_POST['station_name'];
|
||||||
$this->description = $_POST['description'];
|
$this->description = $_POST['description'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,8 +198,8 @@ class ProvisioningHelper
|
||||||
* Initialize preference values passed from the dashboard (if any exist)
|
* Initialize preference values passed from the dashboard (if any exist)
|
||||||
*/
|
*/
|
||||||
private function initializePrefs() {
|
private function initializePrefs() {
|
||||||
if ($this->station_name) {
|
if ($this->stationName) {
|
||||||
Application_Model_Preference::SetStationName($this->station_name);
|
Application_Model_Preference::SetStationName($this->stationName);
|
||||||
}
|
}
|
||||||
if ($this->description) {
|
if ($this->description) {
|
||||||
Application_Model_Preference::SetStationDescription($this->description);
|
Application_Model_Preference::SetStationDescription($this->description);
|
||||||
|
@ -203,3 +207,14 @@ class ProvisioningHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DatabaseAlreadyExistsException extends Exception {
|
||||||
|
private static $_defaultMessage = "ERROR: airtime tables already exists";
|
||||||
|
public function __construct($message = null, $code = 0, Exception $previous = null) {
|
||||||
|
$message = _((is_null($message) ? self::$_defaultMessage : $message));
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseDoesNotExistException extends Exception {}
|
||||||
|
|
||||||
|
|
44
airtime_mvc/application/common/TuneIn.php
Normal file
44
airtime_mvc/application/common/TuneIn.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Application_Common_TuneIn
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param $title url encoded string
|
||||||
|
* @param $artist url encoded string
|
||||||
|
*/
|
||||||
|
public static function sendMetadataToTunein($title, $artist)
|
||||||
|
{
|
||||||
|
$credQryStr = self::getCredentialsQueryString();
|
||||||
|
$metadataQryStr = "&title=".$title."&artist=".$artist."&commercial=false";
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, TUNEIN_API_URL . $credQryStr . $metadataQryStr);
|
||||||
|
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||||
|
|
||||||
|
$xmlResponse = curl_exec($ch);
|
||||||
|
if (curl_error($ch)) {
|
||||||
|
Logging::error("Failed to reach TuneIn: ". curl_errno($ch)." - ". curl_error($ch) . " - " . curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
$xmlObj = new SimpleXMLElement($xmlResponse);
|
||||||
|
if (!$xmlObj || $xmlObj->head->status != "200") {
|
||||||
|
Logging::info("Error occurred pushing metadata to TuneIn:");
|
||||||
|
Logging::info($xmlResponse);
|
||||||
|
} else if ($xmlObj->head->status == "200") {
|
||||||
|
Application_Model_Preference::setLastTuneinMetadataUpdate(time());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCredentialsQueryString() {
|
||||||
|
$tuneInStationID = Application_Model_Preference::getTuneinStationId();
|
||||||
|
$tuneInPartnerID = Application_Model_Preference::getTuneinPartnerId();
|
||||||
|
$tuneInPartnerKey = Application_Model_Preference::getTuneinPartnerKey();
|
||||||
|
|
||||||
|
return "?partnerId=".$tuneInPartnerID."&partnerKey=".$tuneInPartnerKey."&id=".$tuneInStationID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ define('COMPANY_SITE_URL' , 'http://sourcefabric.org/');
|
||||||
define('WHOS_USING_URL' , 'http://sourcefabric.org/en/airtime/whosusing');
|
define('WHOS_USING_URL' , 'http://sourcefabric.org/en/airtime/whosusing');
|
||||||
define('TERMS_AND_CONDITIONS_URL' , 'http://www.sourcefabric.org/en/about/policy/');
|
define('TERMS_AND_CONDITIONS_URL' , 'http://www.sourcefabric.org/en/about/policy/');
|
||||||
define('PRIVACY_POLICY_URL' , 'http://www.sourcefabric.org/en/about/policy/');
|
define('PRIVACY_POLICY_URL' , 'http://www.sourcefabric.org/en/about/policy/');
|
||||||
define('USER_MANUAL_URL' , 'http://sourcefabric.booktype.pro/airtime-25-for-broadcasters/');
|
define('USER_MANUAL_URL' , 'http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters');
|
||||||
|
|
||||||
define('LICENSE_VERSION' , 'GNU AGPL v.3');
|
define('LICENSE_VERSION' , 'GNU AGPL v.3');
|
||||||
define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.html');
|
define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.html');
|
||||||
|
@ -92,3 +92,7 @@ define('SENTRY_CONFIG_PATH', '/etc/airtime-saas/sentry.airtime_web.ini');
|
||||||
//Provisioning status
|
//Provisioning status
|
||||||
define('PROVISIONING_STATUS_SUSPENDED' , 'Suspended');
|
define('PROVISIONING_STATUS_SUSPENDED' , 'Suspended');
|
||||||
define('PROVISIONING_STATUS_ACTIVE' , 'Active');
|
define('PROVISIONING_STATUS_ACTIVE' , 'Active');
|
||||||
|
|
||||||
|
//TuneIn integration
|
||||||
|
define("TUNEIN_API_URL", "http://air.radiotime.com/Playing.ashx");
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ $pages = array(
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'label' => _('User Manual'),
|
'label' => _('User Manual'),
|
||||||
'uri' => "http://sourcefabric.booktype.pro/airtime-25-for-broadcasters/",
|
'uri' => "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters",
|
||||||
'target' => "_blank"
|
'target' => "_blank"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
require_once('WidgetHelper.php');
|
require_once('WidgetHelper.php');
|
||||||
|
require_once('TuneIn.php');
|
||||||
|
|
||||||
class ApiController extends Zend_Controller_Action
|
class ApiController extends Zend_Controller_Action
|
||||||
{
|
{
|
||||||
|
@ -528,6 +529,14 @@ class ApiController extends Zend_Controller_Action
|
||||||
$file = Application_Model_StoredFile::RecallById($file_id);
|
$file = Application_Model_StoredFile::RecallById($file_id);
|
||||||
$now = new DateTime("now", new DateTimeZone("UTC"));
|
$now = new DateTime("now", new DateTimeZone("UTC"));
|
||||||
$file->setLastPlayedTime($now);
|
$file->setLastPlayedTime($now);
|
||||||
|
|
||||||
|
// Push metadata to TuneIn
|
||||||
|
if (Application_Model_Preference::getTuneinEnabled()) {
|
||||||
|
$filePropelOrm = $file->getPropelOrm();
|
||||||
|
$title = urlencode($filePropelOrm->getDbTrackTitle());
|
||||||
|
$artist = urlencode($filePropelOrm->getDbArtistName());
|
||||||
|
Application_Common_TuneIn::sendMetadataToTunein($title, $artist);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// webstream
|
// webstream
|
||||||
|
@ -1419,5 +1428,30 @@ class ApiController extends Zend_Controller_Action
|
||||||
$this->_helper->json($result);
|
$this->_helper->json($result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from PYPO (pypofetch) every 2 minutes and updates
|
||||||
|
* metadata on TuneIn if we haven't done so in the last 4 minutes. We have
|
||||||
|
* to do this because TuneIn turns off metadata if it has not received a
|
||||||
|
* request within 5 minutes. This is necessary for long tracks > 5 minutes.
|
||||||
|
*/
|
||||||
|
public function updateMetadataOnTuneinAction()
|
||||||
|
{
|
||||||
|
if (!Application_Model_Preference::getTuneinEnabled()) {
|
||||||
|
$this->_helper->json->sendJson(array(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastTuneInMetadataUpdate = Application_Model_Preference::geLastTuneinMetadataUpdate();
|
||||||
|
if (time() - $lastTuneInMetadataUpdate >= 240) {
|
||||||
|
$metadata = $metadata = Application_Model_Schedule::getCurrentPlayingTrack();
|
||||||
|
if (!is_null($metadata)) {
|
||||||
|
Application_Common_TuneIn::sendMetadataToTunein(
|
||||||
|
$metadata["title"],
|
||||||
|
$metadata["artist"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->_helper->json->sendJson(array(1));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ class LoginController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
|
//Open the session for writing, because we close it for writing by default in Bootstrap.php as an optimization.
|
||||||
|
session_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
|
|
|
@ -31,6 +31,8 @@ class PlaylistController extends Zend_Controller_Action
|
||||||
->addActionContext('empty-content', 'json')
|
->addActionContext('empty-content', 'json')
|
||||||
->initContext();
|
->initContext();
|
||||||
|
|
||||||
|
//This controller writes to the session all over the place, so we're going to reopen it for writing here.
|
||||||
|
session_start(); //Reopen the session for writing
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPlaylist($p_type)
|
private function getPlaylist($p_type)
|
||||||
|
|
|
@ -32,6 +32,7 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
$form = new Application_Form_Preferences();
|
$form = new Application_Form_Preferences();
|
||||||
$values = array();
|
$values = array();
|
||||||
|
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$values = $request->getPost();
|
$values = $request->getPost();
|
||||||
|
@ -56,16 +57,22 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
Application_Model_Preference::SetStationLogo($imagePath);
|
Application_Model_Preference::SetStationLogo($imagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Application_Model_Preference::SetUploadToSoundcloudOption($values["UploadToSoundcloudOption"]);
|
Application_Model_Preference::setTuneinEnabled($values["enable_tunein"]);
|
||||||
|
Application_Model_Preference::setTuneinStationId($values["tunein_station_id"]);
|
||||||
|
Application_Model_Preference::setTuneinPartnerKey($values["tunein_partner_key"]);
|
||||||
|
Application_Model_Preference::setTuneinPartnerId($values["tunein_partner_id"]);
|
||||||
|
|
||||||
|
/*Application_Model_Preference::SetUploadToSoundcloudOption($values["UploadToSoundcloudOption"]);
|
||||||
Application_Model_Preference::SetSoundCloudDownloadbleOption($values["SoundCloudDownloadbleOption"]);
|
Application_Model_Preference::SetSoundCloudDownloadbleOption($values["SoundCloudDownloadbleOption"]);
|
||||||
Application_Model_Preference::SetSoundCloudUser($values["SoundCloudUser"]);
|
Application_Model_Preference::SetSoundCloudUser($values["SoundCloudUser"]);
|
||||||
Application_Model_Preference::SetSoundCloudPassword($values["SoundCloudPassword"]);
|
Application_Model_Preference::SetSoundCloudPassword($values["SoundCloudPassword"]);
|
||||||
Application_Model_Preference::SetSoundCloudTags($values["SoundCloudTags"]);
|
Application_Model_Preference::SetSoundCloudTags($values["SoundCloudTags"]);
|
||||||
Application_Model_Preference::SetSoundCloudGenre($values["SoundCloudGenre"]);
|
Application_Model_Preference::SetSoundCloudGenre($values["SoundCloudGenre"]);
|
||||||
Application_Model_Preference::SetSoundCloudTrackType($values["SoundCloudTrackType"]);
|
Application_Model_Preference::SetSoundCloudTrackType($values["SoundCloudTrackType"]);
|
||||||
Application_Model_Preference::SetSoundCloudLicense($values["SoundCloudLicense"]);
|
Application_Model_Preference::SetSoundCloudLicense($values["SoundCloudLicense"]);*/
|
||||||
|
|
||||||
$this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
|
$this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
|
||||||
|
$form = new Application_Form_Preferences();
|
||||||
$this->view->form = $form;
|
$this->view->form = $form;
|
||||||
//$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml')));
|
//$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml')));
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,6 +96,8 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/support-setting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/support-setting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->statusMsg = "";
|
$this->view->statusMsg = "";
|
||||||
|
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
$form = new Application_Form_SupportSettings();
|
$form = new Application_Form_SupportSettings();
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$values = $request->getPost();
|
$values = $request->getPost();
|
||||||
|
@ -123,6 +132,8 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function removeLogoAction()
|
public function removeLogoAction()
|
||||||
{
|
{
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
$this->view->layout()->disableLayout();
|
$this->view->layout()->disableLayout();
|
||||||
// Remove reliance on .phtml files to render requests
|
// Remove reliance on .phtml files to render requests
|
||||||
$this->_helper->viewRenderer->setNoRender(true);
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
@ -140,6 +151,8 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
|
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
|
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
// get current settings
|
// get current settings
|
||||||
$setting = Application_Model_StreamSetting::getStreamSetting();
|
$setting = Application_Model_StreamSetting::getStreamSetting();
|
||||||
|
|
||||||
|
@ -176,9 +189,14 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
$num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
|
$num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
|
||||||
$form = new Application_Form_StreamSetting();
|
$form = new Application_Form_StreamSetting();
|
||||||
|
|
||||||
$form->addElement('hash', 'csrf', array(
|
// $form->addElement('hash', 'csrf', array(
|
||||||
'salt' => 'unique'
|
// 'salt' => 'unique'
|
||||||
));
|
// ));
|
||||||
|
|
||||||
|
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
|
||||||
|
$csrf_element = new Zend_Form_Element_Hidden('csrf');
|
||||||
|
$csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label');
|
||||||
|
$form->addElement($csrf_element);
|
||||||
|
|
||||||
$form->setSetting($setting);
|
$form->setSetting($setting);
|
||||||
$form->startFrom();
|
$form->startFrom();
|
||||||
|
@ -425,6 +443,8 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function setSourceConnectionUrlAction()
|
public function setSourceConnectionUrlAction()
|
||||||
{
|
{
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$type = $request->getParam("type", null);
|
$type = $request->getParam("type", null);
|
||||||
$url = urldecode($request->getParam("url", null));
|
$url = urldecode($request->getParam("url", null));
|
||||||
|
@ -443,6 +463,8 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function getAdminPasswordStatusAction()
|
public function getAdminPasswordStatusAction()
|
||||||
{
|
{
|
||||||
|
session_start(); //Open session for writing.
|
||||||
|
|
||||||
$out = array();
|
$out = array();
|
||||||
$num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
|
$num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
|
||||||
for ($i=1; $i<=$num_of_stream; $i++) {
|
for ($i=1; $i<=$num_of_stream; $i++) {
|
||||||
|
@ -454,4 +476,78 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
}
|
}
|
||||||
$this->_helper->json->sendJson($out);
|
$this->_helper->json->sendJson($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteAllFilesAction()
|
||||||
|
{
|
||||||
|
$this->view->layout()->disableLayout();
|
||||||
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
|
// Only admin users should get here through ACL permissioning
|
||||||
|
// Only allow POST requests
|
||||||
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
if (!($method == 'POST')) {
|
||||||
|
$this->getResponse()
|
||||||
|
->setHttpResponseCode(405)
|
||||||
|
->appendBody(_("Request method not accepted") . ": $method");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deleteFutureScheduleItems();
|
||||||
|
$this->deleteCloudFiles();
|
||||||
|
$this->deleteStoredFiles();
|
||||||
|
|
||||||
|
$this->getResponse()
|
||||||
|
->setHttpResponseCode(200)
|
||||||
|
->appendBody("OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteFutureScheduleItems() {
|
||||||
|
$utcTimezone = new DateTimeZone("UTC");
|
||||||
|
$nowDateTime = new DateTime("now", $utcTimezone);
|
||||||
|
$scheduleItems = CcScheduleQuery::create()
|
||||||
|
->filterByDbEnds($nowDateTime->format("Y-m-d H:i:s"), Criteria::GREATER_THAN)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// Delete all the schedule items
|
||||||
|
foreach ($scheduleItems as $i) {
|
||||||
|
// If this is the currently playing track, cancel the current show
|
||||||
|
if ($i->isCurrentItem()) {
|
||||||
|
$instanceId = $i->getDbInstanceId();
|
||||||
|
$instance = CcShowInstancesQuery::create()->findPk($instanceId);
|
||||||
|
$showId = $instance->getDbShowId();
|
||||||
|
|
||||||
|
// From ScheduleController
|
||||||
|
$scheduler = new Application_Model_Scheduler();
|
||||||
|
$scheduler->cancelShow($showId);
|
||||||
|
Application_Model_StoredFile::updatePastFilesIsScheduled();
|
||||||
|
}
|
||||||
|
|
||||||
|
$i->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteCloudFiles() {
|
||||||
|
try {
|
||||||
|
$CC_CONFIG = Config::getConfig();
|
||||||
|
|
||||||
|
foreach ($CC_CONFIG["supportedStorageBackends"] as $storageBackend) {
|
||||||
|
$proxyStorageBackend = new ProxyStorageBackend($storageBackend);
|
||||||
|
$proxyStorageBackend->deleteAllCloudFileObjects();
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
Logging::info($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteStoredFiles() {
|
||||||
|
// Delete all files from the database
|
||||||
|
$files = CcFilesQuery::create()->find();
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$storedFile = new Application_Model_StoredFile($file, null);
|
||||||
|
// Delete the files quietly to avoid getting Sentry errors for
|
||||||
|
// every S3 file we delete.
|
||||||
|
$storedFile->delete(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,16 @@ class ProvisioningController extends Zend_Controller_Action
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the Airtime Pro station's files from Amazon S3
|
* Delete the Airtime Pro station's files from Amazon S3
|
||||||
|
*
|
||||||
|
* FIXME: When we deploy this next time, we should ensure that
|
||||||
|
* this function can only be accessed with POST requests!
|
||||||
*/
|
*/
|
||||||
public function terminateAction()
|
public function terminateAction()
|
||||||
{
|
{
|
||||||
$this->view->layout()->disableLayout();
|
$this->view->layout()->disableLayout();
|
||||||
$this->_helper->viewRenderer->setNoRender(true);
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
if (!RestAuth::verifyAuth(true, true, $this)) {
|
if (!RestAuth::verifyAuth(true, false, $this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
require_once('TuneIn.php');
|
||||||
|
|
||||||
$filepath = realpath (dirname(__FILE__));
|
$filepath = realpath (dirname(__FILE__));
|
||||||
require_once($filepath."/../modules/rest/controllers/MediaController.php");
|
require_once($filepath."/../modules/rest/controllers/MediaController.php");
|
||||||
|
@ -50,6 +51,11 @@ class ScheduleController extends Zend_Controller_Action
|
||||||
|
|
||||||
$baseUrl = Application_Common_OsPath::getBaseDir();
|
$baseUrl = Application_Common_OsPath::getBaseDir();
|
||||||
|
|
||||||
|
//Embed the schedule in our page response so we don't have to make an AJAX request to get this data after the page load.
|
||||||
|
$scheduleController = new ScheduleController($this->getRequest(), $this->getResponse());
|
||||||
|
$scheduleController->eventFeedPreloadAction();
|
||||||
|
$events = json_encode($scheduleController->view->events);
|
||||||
|
|
||||||
$this->view->headScript()->appendScript(
|
$this->view->headScript()->appendScript(
|
||||||
"var calendarPref = {};\n".
|
"var calendarPref = {};\n".
|
||||||
"calendarPref.weekStart = ".Application_Model_Preference::GetWeekStartDay().";\n".
|
"calendarPref.weekStart = ".Application_Model_Preference::GetWeekStartDay().";\n".
|
||||||
|
@ -58,7 +64,7 @@ class ScheduleController extends Zend_Controller_Action
|
||||||
"calendarPref.timeScale = '".Application_Model_Preference::GetCalendarTimeScale()."';\n".
|
"calendarPref.timeScale = '".Application_Model_Preference::GetCalendarTimeScale()."';\n".
|
||||||
"calendarPref.timeInterval = ".Application_Model_Preference::GetCalendarTimeInterval().";\n".
|
"calendarPref.timeInterval = ".Application_Model_Preference::GetCalendarTimeInterval().";\n".
|
||||||
"calendarPref.weekStartDay = ".Application_Model_Preference::GetWeekStartDay().";\n".
|
"calendarPref.weekStartDay = ".Application_Model_Preference::GetWeekStartDay().";\n".
|
||||||
"var calendarEvents = null;"
|
"var calendarEvents = $events;"
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
|
@ -144,7 +150,7 @@ class ScheduleController extends Zend_Controller_Action
|
||||||
} else if ($calendar_interval == "agendaWeek") {
|
} else if ($calendar_interval == "agendaWeek") {
|
||||||
list($start, $end) = Application_Model_Show::getStartEndCurrentWeekView();
|
list($start, $end) = Application_Model_Show::getStartEndCurrentWeekView();
|
||||||
} else if ($calendar_interval == "month") {
|
} else if ($calendar_interval == "month") {
|
||||||
list($start, $end) = Application_Model_Show::getStartEndCurrentMonthView();
|
list($start, $end) = Application_Model_Show::getStartEndCurrentMonthPlusView();
|
||||||
} else {
|
} else {
|
||||||
Logging::error("Invalid Calendar Interval '$calendar_interval'");
|
Logging::error("Invalid Calendar Interval '$calendar_interval'");
|
||||||
}
|
}
|
||||||
|
@ -294,9 +300,21 @@ class ScheduleController extends Zend_Controller_Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This is a nasty hack to let us embed the the data the dashboard needs into the HTML response for each page.
|
||||||
|
* This was originally loaded AFTER page load by AJAX, which is needlessly slow. This should have been templated in.
|
||||||
|
*/
|
||||||
|
public static function printCurrentPlaylistForEmbedding()
|
||||||
|
{
|
||||||
|
$front = Zend_Controller_Front::getInstance();
|
||||||
|
$scheduleController = new ScheduleController($front->getRequest(), $front->getResponse());
|
||||||
|
$scheduleController->getCurrentPlaylistAction();
|
||||||
|
echo(json_encode($scheduleController->view));
|
||||||
|
}
|
||||||
|
|
||||||
public function getCurrentPlaylistAction()
|
public function getCurrentPlaylistAction()
|
||||||
{
|
{
|
||||||
$range = Application_Model_Schedule::GetPlayOrderRangeOld();
|
$range = Application_Model_Schedule::GetPlayOrderRangeOld();
|
||||||
|
|
||||||
$show = Application_Model_Show::getCurrentShow();
|
$show = Application_Model_Show::getCurrentShow();
|
||||||
|
|
||||||
/* Convert all UTC times to localtime before sending back to user. */
|
/* Convert all UTC times to localtime before sending back to user. */
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
//$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
|
||||||
|
|
||||||
|
@ -67,7 +67,8 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
if (isset($values["Privacy"])) {
|
if (isset($values["Privacy"])) {
|
||||||
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
|
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
|
||||||
}
|
}
|
||||||
// unset session
|
session_start(); //open session for writing again
|
||||||
|
// unset referrer
|
||||||
Zend_Session::namespaceUnset('referrer');
|
Zend_Session::namespaceUnset('referrer');
|
||||||
} elseif ($values["Publicise"] == '1' && $form->isValid($values)) {
|
} elseif ($values["Publicise"] == '1' && $form->isValid($values)) {
|
||||||
Application_Model_Preference::SetHeadTitle($values["stnName"], $this->view);
|
Application_Model_Preference::SetHeadTitle($values["stnName"], $this->view);
|
||||||
|
@ -88,7 +89,8 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
if (isset($values["Privacy"])) {
|
if (isset($values["Privacy"])) {
|
||||||
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
|
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
|
||||||
}
|
}
|
||||||
// unset session
|
session_start(); //open session for writing again
|
||||||
|
// unset referrer
|
||||||
Zend_Session::namespaceUnset('referrer');
|
Zend_Session::namespaceUnset('referrer');
|
||||||
} else {
|
} else {
|
||||||
$logo = Application_Model_Preference::GetStationLogo();
|
$logo = Application_Model_Preference::GetStationLogo();
|
||||||
|
@ -156,7 +158,7 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
//populate date range form for show builder.
|
//populate date range form for show builder.
|
||||||
$now = time();
|
$now = time();
|
||||||
$from = $request->getParam("from", $now);
|
$from = $request->getParam("from", $now);
|
||||||
$to = $request->getParam("to", $now + (24*60*60));
|
$to = $request->getParam("to", $now + (3*60*60));
|
||||||
|
|
||||||
$utcTimezone = new DateTimeZone("UTC");
|
$utcTimezone = new DateTimeZone("UTC");
|
||||||
$displayTimeZone = new DateTimeZone(Application_Model_Preference::GetTimezone());
|
$displayTimeZone = new DateTimeZone(Application_Model_Preference::GetTimezone());
|
||||||
|
@ -341,7 +343,8 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$selectedItems = $request->getParam("selectedItem");
|
$selectedItems = $request->getParam("selectedItem");
|
||||||
$afterItem = $request->getParam("afterItem");
|
$afterItem = $request->getParam("afterItem");
|
||||||
|
|
||||||
|
/*
|
||||||
$log_vars = array();
|
$log_vars = array();
|
||||||
$log_vars["url"] = $_SERVER['HTTP_HOST'];
|
$log_vars["url"] = $_SERVER['HTTP_HOST'];
|
||||||
$log_vars["action"] = "showbuilder/schedule-move";
|
$log_vars["action"] = "showbuilder/schedule-move";
|
||||||
|
@ -349,6 +352,7 @@ class ShowbuilderController extends Zend_Controller_Action
|
||||||
$log_vars["params"]["selected_items"] = $selectedItems;
|
$log_vars["params"]["selected_items"] = $selectedItems;
|
||||||
$log_vars["params"]["destination_after_item"] = $afterItem;
|
$log_vars["params"]["destination_after_item"] = $afterItem;
|
||||||
Logging::info($log_vars);
|
Logging::info($log_vars);
|
||||||
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$scheduler = new Application_Model_Scheduler();
|
$scheduler = new Application_Model_Scheduler();
|
||||||
|
|
|
@ -13,16 +13,18 @@ class SystemstatusController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
$services = array(
|
$services = array(
|
||||||
"pypo"=>Application_Model_Systemstatus::GetPypoStatus(),
|
"pypo"=>Application_Model_Systemstatus::GetPypoStatus(),
|
||||||
"liquidsoap"=>Application_Model_Systemstatus::GetLiquidsoapStatus(),
|
"liquidsoap"=>Application_Model_Systemstatus::GetLiquidsoapStatus(),
|
||||||
//"media-monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus(),
|
//"media-monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus(),
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
$partitions = Application_Model_Systemstatus::GetDiskInfo();
|
$partitions = Application_Model_Systemstatus::GetDiskInfo();
|
||||||
|
|
||||||
$this->view->status = new StdClass;
|
$this->view->status = new StdClass;
|
||||||
$this->view->status->services = $services;
|
//$this->view->status->services = $services;
|
||||||
$this->view->status->partitions = $partitions;
|
$this->view->status->partitions = $partitions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ class UserController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function addUserAction()
|
public function addUserAction()
|
||||||
{
|
{
|
||||||
|
// Start the session to re-open write permission to the session so we can
|
||||||
|
// create the namespace for our csrf token verification
|
||||||
|
session_start();
|
||||||
$CC_CONFIG = Config::getConfig();
|
$CC_CONFIG = Config::getConfig();
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
@ -118,7 +121,8 @@ class UserController extends Zend_Controller_Action
|
||||||
}
|
}
|
||||||
|
|
||||||
public function editUserAction()
|
public function editUserAction()
|
||||||
{
|
{
|
||||||
|
session_start(); //Reopen session for writing.
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$form = new Application_Form_EditUser();
|
$form = new Application_Form_EditUser();
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
|
|
|
@ -61,28 +61,23 @@ class UsersettingsController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function getTimelineDatatableAction()
|
public function getTimelineDatatableAction()
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
|
||||||
|
|
||||||
$data = Application_Model_Preference::getTimelineDatatableSetting();
|
$data = Application_Model_Preference::getTimelineDatatableSetting();
|
||||||
if (!is_null($data)) {
|
if (!is_null($data)) {
|
||||||
$this->view->settings = $data;
|
$this->view->settings = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$end = microtime(true);
|
|
||||||
|
|
||||||
Logging::debug("getting timeline datatables info took:");
|
|
||||||
Logging::debug(floatval($end) - floatval($start));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remindmeAction()
|
public function remindmeAction()
|
||||||
{
|
{
|
||||||
// unset session
|
// unset session
|
||||||
|
session_start(); //open session for writing again
|
||||||
Zend_Session::namespaceUnset('referrer');
|
Zend_Session::namespaceUnset('referrer');
|
||||||
Application_Model_Preference::SetRemindMeDate();
|
Application_Model_Preference::SetRemindMeDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remindmeNeverAction()
|
public function remindmeNeverAction()
|
||||||
{
|
{
|
||||||
|
session_start(); //open session for writing again
|
||||||
Zend_Session::namespaceUnset('referrer');
|
Zend_Session::namespaceUnset('referrer');
|
||||||
//pass in true to indicate 'Remind me never' was clicked
|
//pass in true to indicate 'Remind me never' was clicked
|
||||||
Application_Model_Preference::SetRemindMeDate(true);
|
Application_Model_Preference::SetRemindMeDate(true);
|
||||||
|
@ -91,6 +86,7 @@ class UsersettingsController extends Zend_Controller_Action
|
||||||
public function donotshowregistrationpopupAction()
|
public function donotshowregistrationpopupAction()
|
||||||
{
|
{
|
||||||
// unset session
|
// unset session
|
||||||
|
session_start(); //open session for writing again
|
||||||
Zend_Session::namespaceUnset('referrer');
|
Zend_Session::namespaceUnset('referrer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
airtime_mvc/application/forms/DangerousPreferences.php
Normal file
21
airtime_mvc/application/forms/DangerousPreferences.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Application_Form_DangerousPreferences extends Zend_Form_SubForm {
|
||||||
|
|
||||||
|
public function init() {
|
||||||
|
|
||||||
|
$this->setDecorators(array(
|
||||||
|
array('ViewScript', array('viewScript' => 'form/preferences_danger.phtml'))
|
||||||
|
));
|
||||||
|
|
||||||
|
$clearLibrary = new Zend_Form_Element_Button('clear_library');
|
||||||
|
$clearLibrary->setLabel(_('Delete All Tracks in Library'));
|
||||||
|
//$submit->removeDecorator('Label');
|
||||||
|
$clearLibrary->setAttribs(array('class'=>'btn centered'));
|
||||||
|
$clearLibrary->setAttrib('onclick', 'deleteAllFiles();');
|
||||||
|
$clearLibrary->removeDecorator('DtDdWrapper');
|
||||||
|
|
||||||
|
$this->addElement($clearLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,18 +12,30 @@ class Application_Form_Preferences extends Zend_Form
|
||||||
|
|
||||||
$general_pref = new Application_Form_GeneralPreferences();
|
$general_pref = new Application_Form_GeneralPreferences();
|
||||||
|
|
||||||
$this->addElement('hash', 'csrf', array(
|
// $this->addElement('hash', 'csrf', array(
|
||||||
'salt' => 'unique',
|
// 'salt' => 'unique',
|
||||||
'decorators' => array(
|
// 'decorators' => array(
|
||||||
'ViewHelper'
|
// 'ViewHelper'
|
||||||
)
|
// )
|
||||||
));
|
// ));
|
||||||
|
|
||||||
|
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
|
||||||
|
$csrf_element = new Zend_Form_Element_Hidden('csrf');
|
||||||
|
$csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label');
|
||||||
|
$this->addElement($csrf_element);
|
||||||
|
|
||||||
$this->addSubForm($general_pref, 'preferences_general');
|
$this->addSubForm($general_pref, 'preferences_general');
|
||||||
|
|
||||||
|
//tunein form
|
||||||
|
$tuneinPreferences = new Application_Form_TuneInPreferences();
|
||||||
|
$this->addSubForm($tuneinPreferences, 'preferences_tunein');
|
||||||
|
|
||||||
$soundcloud_pref = new Application_Form_SoundcloudPreferences();
|
$soundcloud_pref = new Application_Form_SoundcloudPreferences();
|
||||||
$this->addSubForm($soundcloud_pref, 'preferences_soundcloud');
|
$this->addSubForm($soundcloud_pref, 'preferences_soundcloud');
|
||||||
|
|
||||||
|
$danger_pref = new Application_Form_DangerousPreferences();
|
||||||
|
$this->addSubForm($danger_pref, 'preferences_danger');
|
||||||
|
|
||||||
$submit = new Zend_Form_Element_Submit('submit');
|
$submit = new Zend_Form_Element_Submit('submit');
|
||||||
$submit->setLabel(_('Save'));
|
$submit->setLabel(_('Save'));
|
||||||
//$submit->removeDecorator('Label');
|
//$submit->removeDecorator('Label');
|
||||||
|
|
108
airtime_mvc/application/forms/TuneInPreferences.php
Normal file
108
airtime_mvc/application/forms/TuneInPreferences.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
require_once 'customvalidators/ConditionalNotEmpty.php';
|
||||||
|
|
||||||
|
class Application_Form_TuneInPreferences extends Zend_Form_SubForm
|
||||||
|
{
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setDecorators(array(
|
||||||
|
array('ViewScript', array('viewScript' => 'form/preferences_tunein.phtml'))
|
||||||
|
));
|
||||||
|
|
||||||
|
$enableTunein = new Zend_Form_Element_Checkbox("enable_tunein");
|
||||||
|
$enableTunein->setDecorators(array(
|
||||||
|
'ViewHelper',
|
||||||
|
'Errors',
|
||||||
|
'Label'
|
||||||
|
));
|
||||||
|
$enableTunein->addDecorator('Label', array('class' => 'enable-tunein'));
|
||||||
|
$enableTunein->setLabel(_("Push metadata to your station on TuneIn?"));
|
||||||
|
$enableTunein->setValue(Application_Model_Preference::getTuneinEnabled());
|
||||||
|
$this->addElement($enableTunein);
|
||||||
|
|
||||||
|
$tuneinStationId = new Zend_Form_Element_Text("tunein_station_id");
|
||||||
|
$tuneinStationId->setLabel(_("Station ID:"));
|
||||||
|
$tuneinStationId->setValue(Application_Model_Preference::getTuneinStationId());
|
||||||
|
$tuneinStationId->setAttrib("class", "input_text");
|
||||||
|
$this->addElement($tuneinStationId);
|
||||||
|
|
||||||
|
$tuneinPartnerKey = new Zend_Form_Element_Text("tunein_partner_key");
|
||||||
|
$tuneinPartnerKey->setLabel(_("Partner Key:"));
|
||||||
|
$tuneinPartnerKey->setValue(Application_Model_Preference::getTuneinPartnerKey());
|
||||||
|
$tuneinPartnerKey->setAttrib("class", "input_text");
|
||||||
|
$this->addElement($tuneinPartnerKey);
|
||||||
|
|
||||||
|
$tuneinPartnerId = new Zend_Form_Element_Text("tunein_partner_id");
|
||||||
|
$tuneinPartnerId->setLabel(_("Partner Id:"));
|
||||||
|
$tuneinPartnerId->setValue(Application_Model_Preference::getTuneinPartnerId());
|
||||||
|
$tuneinPartnerId->setAttrib("class", "input_text");
|
||||||
|
$this->addElement($tuneinPartnerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid($data)
|
||||||
|
{
|
||||||
|
$valid = true;
|
||||||
|
// Make request to TuneIn API to test the settings are valid.
|
||||||
|
// TuneIn does not have an API to make test requests to check if
|
||||||
|
// the credentials are correct. Therefore we will make a request
|
||||||
|
// with the commercial flag set to true, which removes the metadata
|
||||||
|
// from the station on TuneIn. After that, and if the test request
|
||||||
|
// succeeds, we will make another request with the real metadata.
|
||||||
|
if ($data["enable_tunein"]) {
|
||||||
|
$credentialsQryStr = "?partnerId=".$data["tunein_partner_id"]."&partnerKey=".$data["tunein_partner_key"]."&id=".$data["tunein_station_id"];
|
||||||
|
$commercialFlagQryStr = "&commercial=true";
|
||||||
|
|
||||||
|
$metadata = Application_Model_Schedule::getCurrentPlayingTrack();
|
||||||
|
|
||||||
|
if (is_null($metadata)) {
|
||||||
|
$qryStr = $credentialsQryStr . $commercialFlagQryStr;
|
||||||
|
} else {
|
||||||
|
$metadata["artist"] = empty($metadata["artist"]) ? "n/a" : $metadata["artist"];
|
||||||
|
$metadata["title"] = empty($metadata["title"]) ? "n/a" : $metadata["title"];
|
||||||
|
$metadataQryStr = "&artist=" . $metadata["artist"] . "&title=" . $metadata["title"];
|
||||||
|
|
||||||
|
$qryStr = $credentialsQryStr . $metadataQryStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, TUNEIN_API_URL . $qryStr);
|
||||||
|
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||||
|
|
||||||
|
$xmlData = curl_exec($ch);
|
||||||
|
if (curl_error($ch)) {
|
||||||
|
Logging::error("Failed to reach TuneIn: ". curl_errno($ch)." - ". curl_error($ch) . " - " . curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
|
||||||
|
if (curl_error($ch) == "The requested URL returned error: 403 Forbidden") {
|
||||||
|
$this->getElement("enable_tunein")->setErrors(array(_("Invalid TuneIn Settings. Please ensure your TuneIn settings are correct and try again.")));
|
||||||
|
$valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($valid) {
|
||||||
|
$xmlObj = new SimpleXMLElement($xmlData);
|
||||||
|
if (!$xmlObj || $xmlObj->head->status != "200") {
|
||||||
|
$this->getElement("enable_tunein")->setErrors(array(_("Invalid TuneIn Settings. Please ensure your TuneIn settings are correct and try again.")));
|
||||||
|
$valid = false;
|
||||||
|
} else if ($xmlObj->head->status == "200") {
|
||||||
|
Application_Model_Preference::setLastTuneinMetadataUpdate(time());
|
||||||
|
$valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$valid) {
|
||||||
|
// Set values to what the user entered since the form is invalid so they
|
||||||
|
// don't have to enter in the values again and can see what they entered.
|
||||||
|
$this->getElement("enable_tunein")->setValue($data["enable_tunein"]);
|
||||||
|
$this->getElement("tunein_partner_key")->setValue($data["tunein_partner_key"]);
|
||||||
|
$this->getElement("tunein_partner_id")->setValue($data["tunein_partner_id"]);
|
||||||
|
$this->getElement("tunein_station_id")->setValue($data["tunein_station_id"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,23 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
"scheduled_play_switch"=>$sss['scheduled_play'])) ?>
|
"scheduled_play_switch"=>$sss['scheduled_play'])) ?>
|
||||||
<?php $partial = array('menu.phtml', 'default');
|
<?php $partial = array('menu.phtml', 'default');
|
||||||
$this->navigation()->menu()->setPartial($partial); ?>
|
$this->navigation()->menu()->setPartial($partial); ?>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var schedulePreLoaded = <?php
|
||||||
|
//Awful hack to speed up loading - Embed the schedule in the response so that the dashboard
|
||||||
|
//doesn't have to make a separate AJAX request to get this data.
|
||||||
|
require_once("ScheduleController.php");
|
||||||
|
ScheduleController::printCurrentPlaylistForEmbedding();
|
||||||
|
?>;
|
||||||
|
//The DOM elements that these calls depend on exist by this point:
|
||||||
|
parseItems(schedulePreLoaded.entries);
|
||||||
|
parseSourceStatus(schedulePreLoaded.source_status);
|
||||||
|
parseSwitchStatus(schedulePreLoaded.switch_status);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
<div class="logo"></div>
|
<div class="logo"></div>
|
||||||
<div class="personal-block solo">
|
<div class="personal-block solo">
|
||||||
|
|
|
@ -1453,4 +1453,54 @@ class Application_Model_Preference
|
||||||
{
|
{
|
||||||
return self::getValue("provisioning_status");
|
return self::getValue("provisioning_status");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function setTuneinEnabled($value)
|
||||||
|
{
|
||||||
|
self::setValue("tunein_enabled", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTuneinEnabled()
|
||||||
|
{
|
||||||
|
return self::getValue("tunein_enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setTuneinPartnerKey($value)
|
||||||
|
{
|
||||||
|
self::setValue("tunein_partner_key", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTuneinPartnerKey()
|
||||||
|
{
|
||||||
|
return self::getValue("tunein_partner_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setTuneinPartnerId($value)
|
||||||
|
{
|
||||||
|
self::setValue("tunein_partner_id", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTuneinPartnerId()
|
||||||
|
{
|
||||||
|
return self::getValue("tunein_partner_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setTuneinStationId($value)
|
||||||
|
{
|
||||||
|
self::setValue("tunein_station_id", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTuneinStationId()
|
||||||
|
{
|
||||||
|
return self::getValue("tunein_station_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function geLastTuneinMetadataUpdate()
|
||||||
|
{
|
||||||
|
return self::getValue("last_tunein_metadata_update");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setLastTuneinMetadataUpdate($value)
|
||||||
|
{
|
||||||
|
self::setValue("last_tunein_metadata_update", $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,12 +112,7 @@ class Application_Model_RabbitMq
|
||||||
$data['original_filename'] = $originalFilename;
|
$data['original_filename'] = $originalFilename;
|
||||||
$data['callback_url'] = $callbackUrl;
|
$data['callback_url'] = $callbackUrl;
|
||||||
$data['api_key'] = $apiKey;
|
$data['api_key'] = $apiKey;
|
||||||
// Pass station name to the analyzer so we can set it with the file's
|
|
||||||
// metadata before uploading it to the cloud. This isn't a requirement
|
|
||||||
// for cloud storage, but put there as a safeguard, since all Airtime
|
|
||||||
// Pro stations will share the same bucket.
|
|
||||||
$data['station_domain'] = $stationDomain = Application_Model_Preference::GetStationName();
|
|
||||||
|
|
||||||
// We add a prefix to the resource name so files are not all placed
|
// We add a prefix to the resource name so files are not all placed
|
||||||
// under the root folder. We do this in case we need to restore a
|
// under the root folder. We do this in case we need to restore a
|
||||||
// customer's file/s; File restoration is done via the S3 Browser
|
// customer's file/s; File restoration is done via the S3 Browser
|
||||||
|
|
|
@ -56,6 +56,29 @@ SQL;
|
||||||
|
|
||||||
return $real_streams;
|
return $real_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with 2 elements: artist and title name of the track that is currently playing.
|
||||||
|
* Elements will be set to null if metadata is not set for those fields.
|
||||||
|
*
|
||||||
|
* Returns null if no track is currently playing.
|
||||||
|
*
|
||||||
|
* Data is based on GetPlayOrderRange() in this class.
|
||||||
|
*/
|
||||||
|
public static function getCurrentPlayingTrack()
|
||||||
|
{
|
||||||
|
$currentScheduleInfo = self::GetPlayOrderRange();
|
||||||
|
if (empty($currentScheduleInfo["tracks"]["current"])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentTrackArray = explode(" - ", $currentScheduleInfo["tracks"]["current"]["name"]);
|
||||||
|
$currentTrackMetadata = array(
|
||||||
|
"artist" => empty($currentTrackArray[0]) ? null : urlencode($currentTrackArray[0]),
|
||||||
|
"title" => empty($currentTrackArray[1]) ? null : urlencode($currentTrackArray[1])
|
||||||
|
);
|
||||||
|
return $currentTrackMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns data related to the scheduled items.
|
* Returns data related to the scheduled items.
|
||||||
|
@ -75,10 +98,8 @@ SQL;
|
||||||
$utcNow = new DateTime("now", new DateTimeZone("UTC"));
|
$utcNow = new DateTime("now", new DateTimeZone("UTC"));
|
||||||
|
|
||||||
$shows = Application_Model_Show::getPrevCurrentNext($utcNow, $utcTimeEnd, $showsToRetrieve);
|
$shows = Application_Model_Show::getPrevCurrentNext($utcNow, $utcTimeEnd, $showsToRetrieve);
|
||||||
$previousShowID = count($shows['previousShow'])>0?$shows['previousShow'][0]['instance_id']:null;
|
|
||||||
$currentShowID = count($shows['currentShow'])>0?$shows['currentShow']['instance_id']:null;
|
$currentShowID = count($shows['currentShow'])>0?$shows['currentShow']['instance_id']:null;
|
||||||
$nextShowID = count($shows['nextShow'])>0?$shows['nextShow'][0]['instance_id']:null;
|
$results = Application_Model_Schedule::getPreviousCurrentNextMedia($utcNow, $currentShowID);
|
||||||
$results = self::GetPrevCurrentNext($previousShowID, $currentShowID, $nextShowID, $utcNow);
|
|
||||||
|
|
||||||
$range = array(
|
$range = array(
|
||||||
"station" => array (
|
"station" => array (
|
||||||
|
@ -113,10 +134,8 @@ SQL;
|
||||||
$utcNow = new DateTime("now", new DateTimeZone("UTC"));
|
$utcNow = new DateTime("now", new DateTimeZone("UTC"));
|
||||||
|
|
||||||
$shows = Application_Model_Show::getPrevCurrentNextOld($utcNow);
|
$shows = Application_Model_Show::getPrevCurrentNextOld($utcNow);
|
||||||
$previousShowID = count($shows['previousShow'])>0?$shows['previousShow'][0]['instance_id']:null;
|
|
||||||
$currentShowID = count($shows['currentShow'])>0?$shows['currentShow'][0]['instance_id']:null;
|
$currentShowID = count($shows['currentShow'])>0?$shows['currentShow'][0]['instance_id']:null;
|
||||||
$nextShowID = count($shows['nextShow'])>0?$shows['nextShow'][0]['instance_id']:null;
|
$results = Application_Model_Schedule::getPreviousCurrentNextMedia($utcNow, $currentShowID);
|
||||||
$results = self::GetPrevCurrentNext($previousShowID, $currentShowID, $nextShowID, $utcNow);
|
|
||||||
|
|
||||||
$range = array(
|
$range = array(
|
||||||
"env" => APPLICATION_ENV,
|
"env" => APPLICATION_ENV,
|
||||||
|
@ -134,129 +153,151 @@ SQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries the database for the set of schedules one hour before
|
* Attempts to find a media item (track or webstream) that is currently playing.
|
||||||
* and after the given time. If a show starts and ends within that
|
* If a current media item is currently playing, this function then attempts to
|
||||||
* time that is considered the current show. Then the scheduled item
|
* find an item that played previously and is scheduled to play next.
|
||||||
* before it is the previous show, and the scheduled item after it
|
*
|
||||||
* is the next show. This way the dashboard getCurrentPlaylist is
|
* @param $utcNow DateTime current time in UTC
|
||||||
* very fast. But if any one of the three show types are not found
|
* @param $currentShowInstanceId cc_show_instance id of the show instance currently playing
|
||||||
* through this mechanism a call is made to the old way of querying
|
* @return array with data about the previous, current, and next media items playing.
|
||||||
* the database to find the track info.
|
* Returns an empty arrays if there is no media item currently playing
|
||||||
**/
|
*/
|
||||||
public static function GetPrevCurrentNext($p_previousShowID, $p_currentShowID, $p_nextShowID, $utcNow)
|
public static function getPreviousCurrentNextMedia($utcNow, $currentShowInstanceId)
|
||||||
{
|
{
|
||||||
$timeZone = new DateTimeZone("UTC"); //This function works entirely in UTC.
|
$timeZone = new DateTimeZone("UTC"); //This function works entirely in UTC.
|
||||||
assert(get_class($utcNow) === "DateTime");
|
assert(get_class($utcNow) === "DateTime");
|
||||||
assert($utcNow->getTimeZone() == $timeZone);
|
assert($utcNow->getTimeZone() == $timeZone);
|
||||||
|
|
||||||
if ($p_previousShowID == null && $p_currentShowID == null && $p_nextShowID == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = "SELECT %%columns%% st.starts as starts, st.ends as ends,
|
|
||||||
st.media_item_played as media_item_played, si.ends as show_ends
|
|
||||||
%%tables%% WHERE ";
|
|
||||||
|
|
||||||
$fileColumns = "ft.artist_name, ft.track_title, ";
|
|
||||||
$fileJoin = "FROM cc_schedule st JOIN cc_files ft ON st.file_id = ft.id
|
|
||||||
LEFT JOIN cc_show_instances si ON st.instance_id = si.id";
|
|
||||||
|
|
||||||
$streamColumns = "ws.name AS artist_name, wm.liquidsoap_data AS track_title, ";
|
|
||||||
$streamJoin = <<<SQL
|
|
||||||
FROM cc_schedule AS st
|
|
||||||
JOIN cc_webstream ws ON st.stream_id = ws.id
|
|
||||||
LEFT JOIN cc_show_instances AS si ON st.instance_id = si.id
|
|
||||||
LEFT JOIN cc_subjs AS sub ON sub.id = ws.creator_id
|
|
||||||
LEFT JOIN
|
|
||||||
(SELECT *
|
|
||||||
FROM cc_webstream_metadata
|
|
||||||
ORDER BY start_time DESC LIMIT 1) AS wm ON st.id = wm.instance_id
|
|
||||||
SQL;
|
|
||||||
|
|
||||||
$predicateArr = array();
|
|
||||||
$paramMap = array();
|
|
||||||
if (isset($p_previousShowID)) {
|
|
||||||
$predicateArr[] = 'st.instance_id = :previousShowId';
|
|
||||||
$paramMap[':previousShowId'] = $p_previousShowID;
|
|
||||||
}
|
|
||||||
if (isset($p_currentShowID)) {
|
|
||||||
$predicateArr[] = 'st.instance_id = :currentShowId';
|
|
||||||
$paramMap[':currentShowId'] = $p_currentShowID;
|
|
||||||
}
|
|
||||||
if (isset($p_nextShowID)) {
|
|
||||||
$predicateArr[] = 'st.instance_id = :nextShowId';
|
|
||||||
$paramMap[':nextShowId'] = $p_nextShowID;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= " (".implode(" OR ", $predicateArr).") ";
|
|
||||||
$sql .= ' AND st.playout_status > 0 ORDER BY st.starts';
|
|
||||||
|
|
||||||
$filesSql = str_replace("%%columns%%", $fileColumns, $sql);
|
|
||||||
$filesSql = str_replace("%%tables%%", $fileJoin, $filesSql);
|
|
||||||
|
|
||||||
$streamSql = str_replace("%%columns%%", $streamColumns, $sql);
|
|
||||||
$streamSql = str_replace("%%tables%%", $streamJoin, $streamSql);
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM (($filesSql) UNION ($streamSql)) AS unioned ORDER BY starts";
|
|
||||||
|
|
||||||
$rows = Application_Common_Database::prepareAndExecute($sql, $paramMap);
|
|
||||||
$numberOfRows = count($rows);
|
|
||||||
|
|
||||||
$results['previous'] = null;
|
$results['previous'] = null;
|
||||||
$results['current'] = null;
|
$results['current'] = null;
|
||||||
$results['next'] = null;
|
$results['next'] = null;
|
||||||
|
|
||||||
for ($i = 0; $i < $numberOfRows; ++$i) {
|
$sql = "select s.id, s.starts, s.ends, s.file_id, s.stream_id, s.media_item_played,
|
||||||
|
s.instance_id, si.ends as show_ends from cc_schedule s left join cc_show_instances si
|
||||||
|
on s.instance_id = si.id where s.playout_status > 0 and s.starts <= :p1
|
||||||
|
and s.ends >= :p2 and s.instance_id = :p3 order by starts desc limit 1";
|
||||||
|
|
||||||
// if the show is overbooked, then update the track end time to the end of the show time.
|
$params = array(
|
||||||
if ($rows[$i]['ends'] > $rows[$i]["show_ends"]) {
|
":p1" => $utcNow->format("Y-m-d H:i:s"),
|
||||||
$rows[$i]['ends'] = $rows[$i]["show_ends"];
|
":p2" => $utcNow->format("Y-m-d H:i:s"),
|
||||||
}
|
":p3" => $currentShowInstanceId
|
||||||
|
);
|
||||||
|
|
||||||
$curShowStartTime = new DateTime($rows[$i]['starts'], $timeZone);
|
$rows = Application_Common_Database::prepareAndExecute($sql, $params);
|
||||||
$curShowEndTime = new DateTime($rows[$i]['ends'], $timeZone);
|
|
||||||
|
|
||||||
if (($curShowStartTime <= $utcNow) && ($curShowEndTime >= $utcNow)) {
|
if (count($rows) < 1) {
|
||||||
if ($i - 1 >= 0) {
|
return $results;
|
||||||
$results['previous'] = array("name"=>$rows[$i-1]["artist_name"]." - ".$rows[$i-1]["track_title"],
|
|
||||||
"starts"=>$rows[$i-1]["starts"],
|
|
||||||
"ends"=>$rows[$i-1]["ends"],
|
|
||||||
"type"=>'track');
|
|
||||||
}
|
|
||||||
$results['current'] = array("name"=>$rows[$i]["artist_name"]." - ".$rows[$i]["track_title"],
|
|
||||||
"starts"=>$rows[$i]["starts"],
|
|
||||||
"ends"=> (($rows[$i]["ends"] > $rows[$i]["show_ends"]) ? $rows[$i]["show_ends"]: $rows[$i]["ends"]),
|
|
||||||
"media_item_played"=>$rows[$i]["media_item_played"],
|
|
||||||
"record"=>0,
|
|
||||||
"type"=>'track');
|
|
||||||
if (isset($rows[$i+1])) {
|
|
||||||
$results['next'] = array("name"=>$rows[$i+1]["artist_name"]." - ".$rows[$i+1]["track_title"],
|
|
||||||
"starts"=>$rows[$i+1]["starts"],
|
|
||||||
"ends"=>$rows[$i+1]["ends"],
|
|
||||||
"type"=>'track');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($curShowEndTime < $utcNow ) {
|
|
||||||
$previousIndex = $i;
|
|
||||||
}
|
|
||||||
if ($curShowStartTime > $utcNow) {
|
|
||||||
$results['next'] = array("name"=>$rows[$i]["artist_name"]." - ".$rows[$i]["track_title"],
|
|
||||||
"starts"=>$rows[$i]["starts"],
|
|
||||||
"ends"=>$rows[$i]["ends"],
|
|
||||||
"type"=>'track');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//If we didn't find a a current show because the time didn't fit we may still have
|
|
||||||
//found a previous show so use it.
|
if ($rows[0]["show_ends"] < $utcNow->format("Y-m-d H:i:s")) {
|
||||||
if ($results['previous'] === null && isset($previousIndex)) {
|
return $results;
|
||||||
$results['previous'] = array("name"=>$rows[$previousIndex]["artist_name"]." - ".$rows[$previousIndex]["track_title"],
|
}
|
||||||
"starts"=>$rows[$previousIndex]["starts"],
|
|
||||||
"ends"=>$rows[$previousIndex]["ends"]);;
|
$currentMedia = $rows[0];
|
||||||
|
|
||||||
|
if ($currentMedia["ends"] > $currentMedia["show_ends"]) {
|
||||||
|
$currentMedia["ends"] = $currentMedia["show_ends"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentMediaFileId = $currentMedia["file_id"];
|
||||||
|
$currentMediaStreamId = $currentMedia["stream_id"];
|
||||||
|
if (isset($currentMediaFileId)) {
|
||||||
|
$currentMediaType = "track";
|
||||||
|
$currentFile = CcFilesQuery::create()
|
||||||
|
->filterByDbId($currentMediaFileId)
|
||||||
|
->findOne();
|
||||||
|
$currentMediaName = $currentFile->getDbArtistName() . " - " . $currentFile->getDbTrackTitle();
|
||||||
|
} else if (isset($currentMediaStreamId)) {
|
||||||
|
$currentMediaType = "webstream";
|
||||||
|
$currentWebstream = CcWebstreamQuery::create()
|
||||||
|
->filterByDbId($currentMediaStreamId)
|
||||||
|
->findOne();
|
||||||
|
$currentWebstreamMetadata = CcWebstreamMetadataQuery::create()
|
||||||
|
->filterByDbInstanceId($currentMedia["instance_id"])
|
||||||
|
->orderByDbStartTime(Criteria::DESC)
|
||||||
|
->findOne();
|
||||||
|
$currentMediaName = $currentWebstream->getDbName();
|
||||||
|
if (isset($currentWebstreamMetadata)) {
|
||||||
|
$currentMediaName .= " - " . $currentWebstreamMetadata->getDbLiquidsoapData();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$currentMediaType = null;
|
||||||
|
}
|
||||||
|
$results["current"] = array(
|
||||||
|
"starts" => $currentMedia["starts"],
|
||||||
|
"ends" => $currentMedia["ends"],
|
||||||
|
"type" => $currentMediaType,
|
||||||
|
"name" => $currentMediaName,
|
||||||
|
"media_item_played" => $currentMedia["media_item_played"],
|
||||||
|
"record" => "0"
|
||||||
|
);
|
||||||
|
|
||||||
|
$previousMedia = CcScheduleQuery::create()
|
||||||
|
->filterByDbStarts($currentMedia["starts"], Criteria::LESS_THAN)
|
||||||
|
->filterByDbId($currentMedia["id"], Criteria::NOT_EQUAL)
|
||||||
|
->filterByDbPlayoutStatus(0, Criteria::GREATER_THAN)
|
||||||
|
->orderByDbStarts(Criteria::DESC)
|
||||||
|
->findOne();
|
||||||
|
if (isset($previousMedia)) {
|
||||||
|
$previousMediaFileId = $previousMedia->getDbFileId();
|
||||||
|
$previousMediaStreamId = $previousMedia->getDbStreamId();
|
||||||
|
if (isset($previousMediaFileId)) {
|
||||||
|
$previousMediaType = "track";
|
||||||
|
$previousFile = CcFilesQuery::create()
|
||||||
|
->filterByDbId($previousMediaFileId)
|
||||||
|
->findOne();
|
||||||
|
$previousMediaName = $previousFile->getDbArtistName() . " - " . $previousFile->getDbTrackTitle();
|
||||||
|
} else if (isset($previousMediaStreamId)) {
|
||||||
|
$previousMediaName = null;
|
||||||
|
$previousMediaType = "webstream";
|
||||||
|
$previousWebstream = CcWebstreamQuery::create()
|
||||||
|
->filterByDbId($previousMediaStreamId)
|
||||||
|
->findOne();
|
||||||
|
$previousMediaName = $previousWebstream->getDbName();
|
||||||
|
} else {
|
||||||
|
$previousMediaType = null;
|
||||||
|
}
|
||||||
|
$results["previous"] = array(
|
||||||
|
"starts" => $previousMedia->getDbStarts(),
|
||||||
|
"ends" => $previousMedia->getDbEnds(),
|
||||||
|
"type" => $previousMediaType,
|
||||||
|
"name" => $previousMediaName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nextMedia = CcScheduleQuery::create()
|
||||||
|
->filterByDbStarts($currentMedia["starts"], Criteria::GREATER_THAN)
|
||||||
|
->filterByDbId($currentMedia["id"], Criteria::NOT_EQUAL)
|
||||||
|
->orderByDbStarts(Criteria::ASC)
|
||||||
|
->findOne();
|
||||||
|
if (isset($nextMedia)) {
|
||||||
|
$nextMediaFileId = $nextMedia->getDbFileId();
|
||||||
|
$nextMediaStreamId = $nextMedia->getDbStreamId();
|
||||||
|
if (isset($nextMediaFileId)) {
|
||||||
|
$nextMediaType = "track";
|
||||||
|
$nextFile = CcFilesQuery::create()
|
||||||
|
->filterByDbId($nextMediaFileId)
|
||||||
|
->findOne();
|
||||||
|
$nextMediaName = $nextFile->getDbArtistName() . " - " . $nextFile->getDbTrackTitle();
|
||||||
|
} else if (isset($nextMediaStreamId)) {
|
||||||
|
$nextMediaType = "webstream";
|
||||||
|
$nextWebstream = CcWebstreamQuery::create()
|
||||||
|
->filterByDbId($nextMediaStreamId)
|
||||||
|
->findOne();
|
||||||
|
$nextMediaName = $nextWebstream->getDbName();
|
||||||
|
} else {
|
||||||
|
$nextMediaType = null;
|
||||||
|
}
|
||||||
|
$results["next"] = array(
|
||||||
|
"starts" => $nextMedia->getDbStarts(),
|
||||||
|
"ends" => $nextMedia->getDbEnds(),
|
||||||
|
"type" => $nextMediaType,
|
||||||
|
"name" => $nextMediaName
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function GetLastScheduleItem($p_timeNow)
|
public static function GetLastScheduleItem($p_timeNow)
|
||||||
|
|
|
@ -1012,10 +1012,10 @@ class Application_Model_Scheduler
|
||||||
*/
|
*/
|
||||||
public function moveItem($selectedItems, $afterItems, $adjustSched = true)
|
public function moveItem($selectedItems, $afterItems, $adjustSched = true)
|
||||||
{
|
{
|
||||||
$startProfile = microtime(true);
|
//$startProfile = microtime(true);
|
||||||
|
|
||||||
$this->con->beginTransaction();
|
$this->con->beginTransaction();
|
||||||
$this->con->useDebug(true);
|
//$this->con->useDebug(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -1024,8 +1024,8 @@ class Application_Model_Scheduler
|
||||||
$this->validateRequest($afterItems);
|
$this->validateRequest($afterItems);
|
||||||
|
|
||||||
$endProfile = microtime(true);
|
$endProfile = microtime(true);
|
||||||
Logging::debug("validating move request took:");
|
//Logging::debug("validating move request took:");
|
||||||
Logging::debug(floatval($endProfile) - floatval($startProfile));
|
//Logging::debug(floatval($endProfile) - floatval($startProfile));
|
||||||
|
|
||||||
$afterInstance = CcShowInstancesQuery::create()->findPK($afterItems[0]["instance"], $this->con);
|
$afterInstance = CcShowInstancesQuery::create()->findPK($afterItems[0]["instance"], $this->con);
|
||||||
|
|
||||||
|
@ -1066,18 +1066,18 @@ class Application_Model_Scheduler
|
||||||
|
|
||||||
$this->removeGaps($instance, $schedIds);
|
$this->removeGaps($instance, $schedIds);
|
||||||
|
|
||||||
$endProfile = microtime(true);
|
//$endProfile = microtime(true);
|
||||||
Logging::debug("removing gaps from instance $instance:");
|
//Logging::debug("removing gaps from instance $instance:");
|
||||||
Logging::debug(floatval($endProfile) - floatval($startProfile));
|
//Logging::debug(floatval($endProfile) - floatval($startProfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
$startProfile = microtime(true);
|
//$startProfile = microtime(true);
|
||||||
|
|
||||||
$this->insertAfter($afterItems, null, $movedData, $adjustSched, true);
|
$this->insertAfter($afterItems, null, $movedData, $adjustSched, true);
|
||||||
|
|
||||||
$endProfile = microtime(true);
|
//$endProfile = microtime(true);
|
||||||
Logging::debug("inserting after removing gaps.");
|
//Logging::debug("inserting after removing gaps.");
|
||||||
Logging::debug(floatval($endProfile) - floatval($startProfile));
|
//Logging::debug(floatval($endProfile) - floatval($startProfile));
|
||||||
|
|
||||||
$modified = array_keys($modifiedMap);
|
$modified = array_keys($modifiedMap);
|
||||||
//need to adjust shows we have moved items from.
|
//need to adjust shows we have moved items from.
|
||||||
|
@ -1087,7 +1087,7 @@ class Application_Model_Scheduler
|
||||||
$instance->updateScheduleStatus($this->con);
|
$instance->updateScheduleStatus($this->con);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->con->useDebug(false);
|
//$this->con->useDebug(false);
|
||||||
$this->con->commit();
|
$this->con->commit();
|
||||||
|
|
||||||
Application_Model_RabbitMq::PushSchedule();
|
Application_Model_RabbitMq::PushSchedule();
|
||||||
|
|
|
@ -974,10 +974,7 @@ SQL;
|
||||||
foreach ($shows as &$show) {
|
foreach ($shows as &$show) {
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
//only bother calculating percent for week or day view.
|
$options["percent"] = Application_Model_Show::getPercentScheduled($show["starts"], $show["ends"], $show["time_filled"]);
|
||||||
if (intval($days) <= 7) {
|
|
||||||
$options["percent"] = Application_Model_Show::getPercentScheduled($show["starts"], $show["ends"], $show["time_filled"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($show["parent_starts"])) {
|
if (isset($show["parent_starts"])) {
|
||||||
$parentStartsDT = new DateTime($show["parent_starts"], $utcTimezone);
|
$parentStartsDT = new DateTime($show["parent_starts"], $utcTimezone);
|
||||||
|
@ -1432,39 +1429,70 @@ SQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStartEndCurrentMonthView() {
|
public static function getStartEndCurrentMonthView() {
|
||||||
$first_day_of_calendar_month_view = mktime(0, 0, 0, date("n"), 1);
|
|
||||||
$weekStart = Application_Model_Preference::GetWeekStartDay();
|
|
||||||
while (date('w', $first_day_of_calendar_month_view) != $weekStart) {
|
|
||||||
$first_day_of_calendar_month_view -= 60*60*24;
|
|
||||||
}
|
|
||||||
$last_day_of_calendar_view = $first_day_of_calendar_month_view + 3600*24*42;
|
|
||||||
|
|
||||||
$start = new DateTime("@".$first_day_of_calendar_month_view);
|
$utcTimeZone = new DateTimeZone("UTC");
|
||||||
$end = new DateTime("@".$last_day_of_calendar_view);
|
|
||||||
|
//We have to get the start of the day in the user's timezone, and then convert that to UTC.
|
||||||
|
$start = new DateTime("first day of this month", new DateTimeZone(Application_Model_Preference::GetUserTimezone()));
|
||||||
|
|
||||||
|
$start->setTimezone($utcTimeZone); //Covert it to UTC.
|
||||||
|
$monthInterval = new DateInterval("P1M");
|
||||||
|
$end = clone($start);
|
||||||
|
$end->add($monthInterval);
|
||||||
|
|
||||||
return array($start, $end);
|
return array($start, $end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the start and end date that FullCalendar will display for today's month.
|
||||||
|
*
|
||||||
|
* FullCalendar displays 6 weeks, starting on a Sunday, for a total of 42 days. This function returns 42 days worth
|
||||||
|
* of data (a few days before, and a few days after.)
|
||||||
|
*/
|
||||||
|
public static function getStartEndCurrentMonthPlusView() {
|
||||||
|
|
||||||
|
$utcTimeZone = new DateTimeZone("UTC");
|
||||||
|
|
||||||
|
//We have to get the start of the day in the user's timezone, and then convert that to UTC.
|
||||||
|
$start = new DateTime("first day of this month", new DateTimeZone(Application_Model_Preference::GetUserTimezone()));
|
||||||
|
|
||||||
|
$dayOfWeekNumeric = $start->format('w');
|
||||||
|
$start->sub(new DateInterval("P{$dayOfWeekNumeric}D")); //Subtract the index of the day of the week the month starts on. (adds this many days from the previous month)
|
||||||
|
$start->setTimezone($utcTimeZone); //Covert it to UTC.
|
||||||
|
|
||||||
|
$fullCalendarMonthInterval = new DateInterval("P42D"); //42 days
|
||||||
|
$end = clone($start);
|
||||||
|
$end->add($fullCalendarMonthInterval);
|
||||||
|
|
||||||
|
return array($start, $end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getStartEndCurrentWeekView() {
|
public static function getStartEndCurrentWeekView() {
|
||||||
$first_day_of_calendar_week_view = mktime(0, 0, 0, date("n"), date("j"));
|
|
||||||
$weekStart = Application_Model_Preference::GetWeekStartDay();
|
|
||||||
while (date('w', $first_day_of_calendar_week_view) != $weekStart) {
|
|
||||||
$first_day_of_calendar_week_view -= 60*60*24;
|
|
||||||
}
|
|
||||||
$last_day_of_calendar_view = $first_day_of_calendar_week_view + 3600*24*7;
|
|
||||||
|
|
||||||
$start = new DateTime("@".$first_day_of_calendar_week_view);
|
$weekStartDayNum = Application_Model_Preference::GetWeekStartDay();
|
||||||
$end = new DateTime("@".$last_day_of_calendar_view);
|
$utcTimeZone = new DateTimeZone("UTC");
|
||||||
|
|
||||||
|
//We have to get the start of the week in the user's timezone, and then convert that to UTC.
|
||||||
|
$start = new DateTime("Sunday last week", new DateTimeZone(Application_Model_Preference::GetUserTimezone()));
|
||||||
|
$start->add(new DateInterval("P{$weekStartDayNum}D")); //Shift the start date to the station's "Week Starts on Day"
|
||||||
|
|
||||||
|
$start->setTimezone($utcTimeZone); //Covert it to UTC.
|
||||||
|
$weekInterval = new DateInterval("P1W");
|
||||||
|
$end = clone($start);
|
||||||
|
$end->add($weekInterval);
|
||||||
return array($start, $end);
|
return array($start, $end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStartEndCurrentDayView() {
|
public static function getStartEndCurrentDayView() {
|
||||||
$today = mktime(0, 0, 0, date("n"), date("j"));
|
$utcTimeZone = new DateTimeZone("UTC");
|
||||||
$tomorrow = $today + 3600*24;
|
|
||||||
|
|
||||||
$start = new DateTime("@".$today);
|
//We have to get the start of the day in the user's timezone, and then convert that to UTC.
|
||||||
$end = new DateTime("@".$tomorrow);
|
$start = new DateTime("today", new DateTimeZone(Application_Model_Preference::GetUserTimezone()));
|
||||||
|
|
||||||
|
$start->setTimezone($utcTimeZone); //Covert it to UTC.
|
||||||
|
$dayInterval = new DateInterval("P1D");
|
||||||
|
$end = clone($start);
|
||||||
|
$end->add($dayInterval);
|
||||||
|
|
||||||
return array($start, $end);
|
return array($start, $end);
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ SQL;
|
||||||
* Deletes the physical file from the local file system or from the cloud
|
* Deletes the physical file from the local file system or from the cloud
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete($quiet=false)
|
||||||
{
|
{
|
||||||
// Check if the file is scheduled to be played in the future
|
// Check if the file is scheduled to be played in the future
|
||||||
if (Application_Model_Schedule::IsFileScheduledInTheFuture($this->_file->getCcFileId())) {
|
if (Application_Model_Schedule::IsFileScheduledInTheFuture($this->_file->getCcFileId())) {
|
||||||
|
@ -405,8 +405,12 @@ SQL;
|
||||||
}
|
}
|
||||||
catch (Exception $e)
|
catch (Exception $e)
|
||||||
{
|
{
|
||||||
//Just log the exception and continue.
|
if ($quiet) {
|
||||||
Logging::error($e);
|
Logging::info($e);
|
||||||
|
} else {
|
||||||
|
//Just log the exception and continue.
|
||||||
|
Logging::error($e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,23 +150,27 @@ class Application_Service_CalendarService
|
||||||
$menu["edit"] = array(
|
$menu["edit"] = array(
|
||||||
"name" => _("Edit This Instance"),
|
"name" => _("Edit This Instance"),
|
||||||
"icon" => "edit",
|
"icon" => "edit",
|
||||||
"url" => $baseUrl."Schedule/populate-repeating-show-instance-form");
|
"url" => $baseUrl . "Schedule/populate-repeating-show-instance-form"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$menu["edit"] = array(
|
$menu["edit"] = array(
|
||||||
"name" => _("Edit"),
|
"name" => _("Edit"),
|
||||||
"icon" => "edit",
|
"icon" => "edit",
|
||||||
"items" => array());
|
"items" => array()
|
||||||
|
);
|
||||||
|
|
||||||
$menu["edit"]["items"]["all"] = array(
|
$menu["edit"]["items"]["all"] = array(
|
||||||
"name" => _("Edit Show"),
|
"name" => _("Edit Show"),
|
||||||
"icon" => "edit",
|
"icon" => "edit",
|
||||||
"url" => $baseUrl."Schedule/populate-show-form");
|
"url" => $baseUrl . "Schedule/populate-show-form"
|
||||||
|
);
|
||||||
|
|
||||||
$menu["edit"]["items"]["instance"] = array(
|
$menu["edit"]["items"]["instance"] = array(
|
||||||
"name" => _("Edit This Instance"),
|
"name" => _("Edit This Instance"),
|
||||||
"icon" => "edit",
|
"icon" => "edit",
|
||||||
"url" => $baseUrl."Schedule/populate-repeating-show-instance-form");
|
"url" => $baseUrl . "Schedule/populate-repeating-show-instance-form"
|
||||||
}
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$menu["edit"] = array(
|
$menu["edit"] = array(
|
||||||
"name"=> _("Edit Show"),
|
"name"=> _("Edit Show"),
|
||||||
|
|
|
@ -153,14 +153,19 @@ class Application_Service_ShowFormService
|
||||||
if ($ccShowDay->isShowStartInPast()) {
|
if ($ccShowDay->isShowStartInPast()) {
|
||||||
//for a non-repeating show, we should never allow user to change the start time.
|
//for a non-repeating show, we should never allow user to change the start time.
|
||||||
//for a repeating show, we should allow because the form works as repeating template form
|
//for a repeating show, we should allow because the form works as repeating template form
|
||||||
if (!$ccShowDay->isRepeating()) {
|
$form->disableStartDateAndTime();
|
||||||
|
|
||||||
|
// Removing this - if there is no future instance, this will throw an error.
|
||||||
|
// If there is a future instance, then we get a WHEN block representing the next instance
|
||||||
|
// which may be confusing.
|
||||||
|
/*if (!$ccShowDay->isRepeating()) {
|
||||||
$form->disableStartDateAndTime();
|
$form->disableStartDateAndTime();
|
||||||
} else {
|
} else {
|
||||||
list($showStart, $showEnd) = $this->getNextFutureRepeatShowTime();
|
list($showStart, $showEnd) = $this->getNextFutureRepeatShowTime();
|
||||||
if ($this->hasShowStarted($showStart)) {
|
if ($this->hasShowStarted($showStart)) {
|
||||||
$form->disableStartDateAndTime();
|
$form->disableStartDateAndTime();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
$form->populate(
|
$form->populate(
|
||||||
|
@ -410,9 +415,8 @@ class Application_Service_ShowFormService
|
||||||
|
|
||||||
//if the show is repeating, set the start date to the next
|
//if the show is repeating, set the start date to the next
|
||||||
//repeating instance in the future
|
//repeating instance in the future
|
||||||
if ($this->ccShow->isRepeating()) {
|
$originalShowStartDateTime = $this->getCurrentOrNextInstanceStartTime();
|
||||||
list($originalShowStartDateTime,) = $this->getNextFutureRepeatShowTime();
|
if (!$originalShowStartDateTime) {
|
||||||
} else {
|
|
||||||
$originalShowStartDateTime = $dt;
|
$originalShowStartDateTime = $dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,26 +425,30 @@ class Application_Service_ShowFormService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Returns 2 DateTime objects, in the user's local time,
|
* Returns a DateTime object, in the user's local time,
|
||||||
* of the next future repeat show instance start and end time
|
* of the current or next show instance start time
|
||||||
|
*
|
||||||
|
* Returns null if there is no next future repeating show instance
|
||||||
*/
|
*/
|
||||||
public function getNextFutureRepeatShowTime()
|
public function getCurrentOrNextInstanceStartTime()
|
||||||
{
|
{
|
||||||
$ccShowInstance = CcShowInstancesQuery::create()
|
$ccShowInstance = CcShowInstancesQuery::create()
|
||||||
->filterByDbShowId($this->ccShow->getDbId())
|
->filterByDbShowId($this->ccShow->getDbId())
|
||||||
->filterByDbModifiedInstance(false)
|
->filterByDbModifiedInstance(false)
|
||||||
->filterByDbStarts(gmdate("Y-m-d H:i:s"), Criteria::GREATER_THAN)
|
->filterByDbStarts(gmdate("Y-m-d"), Criteria::GREATER_EQUAL)
|
||||||
->orderByDbStarts()
|
->orderByDbStarts()
|
||||||
->findOne();
|
->findOne();
|
||||||
|
|
||||||
|
if (!$ccShowInstance) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$starts = new DateTime($ccShowInstance->getDbStarts(), new DateTimeZone("UTC"));
|
$starts = new DateTime($ccShowInstance->getDbStarts(), new DateTimeZone("UTC"));
|
||||||
$ends = new DateTime($ccShowInstance->getDbEnds(), new DateTimeZone("UTC"));
|
|
||||||
$showTimezone = $this->ccShow->getFirstCcShowDay()->getDbTimezone();
|
$showTimezone = $this->ccShow->getFirstCcShowDay()->getDbTimezone();
|
||||||
|
|
||||||
$starts->setTimezone(new DateTimeZone($showTimezone));
|
$starts->setTimezone(new DateTimeZone($showTimezone));
|
||||||
$ends->setTimezone(new DateTimeZone($showTimezone));
|
|
||||||
|
|
||||||
return array($starts, $ends);
|
return $starts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,22 @@
|
||||||
<?php echo $this->element->getElement('csrf') ?>
|
<?php echo $this->element->getElement('csrf') ?>
|
||||||
|
|
||||||
<?php echo $this->element->getSubform('preferences_general') ?>
|
<?php echo $this->element->getSubform('preferences_general') ?>
|
||||||
|
|
||||||
|
<h3 class="collapsible-header" id="tunein-pref-heading"><span class="arrow-icon"></span><?php echo _("TuneIn Settings"); ?></h3>
|
||||||
|
<div class="collapsible-content" id="tunein-settings">
|
||||||
|
<?php echo $this->element->getSubform('preferences_tunein') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<?php //No soundcloud stuff on Airtime Pro -- Albert ?>
|
<?php //No soundcloud stuff on Airtime Pro -- Albert ?>
|
||||||
|
|
||||||
|
<h3 class="collapsible-header" id="dangerous-heading"><span class="arrow-icon"></span><?php echo _("Dangerous Options") ?></h3>
|
||||||
|
<div class="collapsible-content" id="dangerous-settings">
|
||||||
|
<?php echo $this->element->getSubform('preferences_danger') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
<?php echo $this->element->submit->render() ?>
|
<?php echo $this->element->submit->render() ?>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<fieldset class="padded">
|
||||||
|
<dl class="zend_form">
|
||||||
|
|
||||||
|
<div class="warning" style="margin-bottom: 10px;">
|
||||||
|
<p class="warning-label">
|
||||||
|
<strong>Warning:</strong> These functions will have <strong>permanent and lasting effects</strong>
|
||||||
|
on your Airtime station. Think carefully before using them!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php echo $this->element->getElement('clear_library')->render() ?>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<fieldset class="padded">
|
||||||
|
<dl class="zend_form">
|
||||||
|
|
||||||
|
<?php if($this->element->getElement("enable_tunein")->hasErrors()) {
|
||||||
|
echo $this->element->getElement('enable_tunein')->renderErrors();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php echo $this->element->getElement('enable_tunein')->renderViewHelper() ?>
|
||||||
|
<?php echo $this->element->getElement('enable_tunein')->renderLabel() ?>
|
||||||
|
|
||||||
|
<?php echo $this->element->getElement('tunein_station_id')->render() ?>
|
||||||
|
|
||||||
|
<?php echo $this->element->getElement('tunein_partner_id')->render() ?>
|
||||||
|
|
||||||
|
<?php echo $this->element->getElement('tunein_partner_key')->render() ?>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
|
@ -3,12 +3,11 @@
|
||||||
font-size: 200px !important;
|
font-size: 200px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<?php $upgradeLink = Application_Common_OsPath::getBaseDir() . "billing/upgrade"; ?>
|
||||||
<?php if ($this->quotaLimitReached) { ?>
|
<?php if ($this->quotaLimitReached) { ?>
|
||||||
<div class="errors quota-reached">
|
<div class="errors quota-reached">
|
||||||
Disk quota exceeded. You cannot upload files until you
|
<?php printf(_pro("Disk quota exceeded. You cannot upload files until you %s upgrade your storage"),
|
||||||
<a target="_parent" href=<?php $baseUrl = Application_Common_OsPath::getBaseDir(); echo $baseUrl . "billing/upgrade"?>>
|
"<a target=\"_parent\" href=$upgradeLink>");?></a>.
|
||||||
upgrade your storage
|
|
||||||
</a>.
|
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,6 @@
|
||||||
<table width="60%" cellpadding="0" cellspacing="0" border="0" class="statustable">
|
<table width="60%" cellpadding="0" cellspacing="0" border="0" class="statustable">
|
||||||
<thead>
|
|
||||||
<tr class="ui-state-default strong">
|
|
||||||
<td><?php echo _("Service") ?></td>
|
|
||||||
<td><?php echo _("Status") ?></td>
|
|
||||||
<td><?php echo _("Uptime") ?></td>
|
|
||||||
<td><?php echo _("CPU") ?></td>
|
|
||||||
<td><?php echo _("Memory") ?></td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<!--
|
|
||||||
<tr class="odd">
|
|
||||||
<td><?php echo sprintf(_("%s Version"), PRODUCT_NAME) ?></td>
|
|
||||||
<td>1.9.3</td>
|
|
||||||
<td> </td>
|
|
||||||
</tr>
|
|
||||||
-->
|
|
||||||
<?php $i=0; ?>
|
|
||||||
<?php foreach($this->status->services as $key=>$value): ?>
|
|
||||||
<tr class="<?php echo ($i&1) == 0 ? "even":"odd"; $i++; ?>" id="<?php echo $value["name"]; ?>">
|
|
||||||
<td><?php echo $value["name"]; ?></td>
|
|
||||||
<td><span></span></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<tr id="partitions" class="even">
|
<tr id="partitions" class="even">
|
||||||
<th colspan="5"><?php echo _("Disk Space") ?></th>
|
<th colspan="5"><?php echo _("Disk Space") ?></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -1788,7 +1788,7 @@ ul.errors {
|
||||||
width:278px;
|
width:278px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.errors li {
|
ul.errors li, .warning {
|
||||||
color:#902d2d;
|
color:#902d2d;
|
||||||
font-size:11px;
|
font-size:11px;
|
||||||
padding:2px 4px;
|
padding:2px 4px;
|
||||||
|
@ -1798,6 +1798,11 @@ ul.errors li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning-label {
|
||||||
|
font-size: medium;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
div.success{
|
div.success{
|
||||||
color:#3B5323;
|
color:#3B5323;
|
||||||
font-size:11px;
|
font-size:11px;
|
||||||
|
@ -2255,14 +2260,9 @@ dd.radio-inline-list, .preferences dd.radio-inline-list, .stream-config dd.radio
|
||||||
.radio-inline-list label {
|
.radio-inline-list label {
|
||||||
margin-right:12px;
|
margin-right:12px;
|
||||||
}
|
}
|
||||||
.preferences.simple-formblock dd.block-display {
|
.preferences.simple-formblock dd.block-display,
|
||||||
width: 100%;
|
.preferences.simple-formblock dd.block-display select, .stream-config.simple-formblock dd.block-display select,
|
||||||
}
|
.preferences dd.block-display .input_select, .stream-config dd.block-display .input_select {
|
||||||
|
|
||||||
.preferences.simple-formblock dd.block-display select, .stream-config.simple-formblock dd.block-display select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.preferences dd.block-display .input_select, .stream-config dd.block-display .input_select {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.preferences dd.block-display .input_text_area, .preferences dd.block-display .input_text
|
.preferences dd.block-display .input_text_area, .preferences dd.block-display .input_text
|
||||||
|
@ -2284,6 +2284,15 @@ dd.radio-inline-list, .preferences dd.radio-inline-list, .stream-config dd.radio
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preferences #Logo-img-container {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
#show_time_info {
|
#show_time_info {
|
||||||
font-size:12px;
|
font-size:12px;
|
||||||
height:30px;
|
height:30px;
|
||||||
|
@ -3248,3 +3257,7 @@ dd .stream-status {
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
padding-top: 13px;
|
padding-top: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.enable-tunein {
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
|
@ -395,7 +395,6 @@ function getScheduleFromServer(){
|
||||||
parseSourceStatus(data.source_status);
|
parseSourceStatus(data.source_status);
|
||||||
parseSwitchStatus(data.switch_status);
|
parseSwitchStatus(data.switch_status);
|
||||||
showName = data.show_name;
|
showName = data.show_name;
|
||||||
setTimeout(getScheduleFromServer, serverUpdateInterval);
|
|
||||||
}, error:function(jqXHR, textStatus, errorThrown){}});
|
}, error:function(jqXHR, textStatus, errorThrown){}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,8 +455,8 @@ var stream_window = null;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
//begin producer "thread"
|
//begin producer "thread"
|
||||||
getScheduleFromServer();
|
setInterval(getScheduleFromServer, serverUpdateInterval);
|
||||||
|
|
||||||
//begin consumer "thread"
|
//begin consumer "thread"
|
||||||
secondsTimer();
|
secondsTimer();
|
||||||
|
|
||||||
|
|
|
@ -213,3 +213,21 @@ function resizeToMaxHeight(ele, targetHeight){
|
||||||
img.css("width", newWidth+"px");
|
img.css("width", newWidth+"px");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* From http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport/#7557433 */
|
||||||
|
function isInView(el) {
|
||||||
|
//special bonus for those using jQuery
|
||||||
|
if (typeof jQuery === "function" && el instanceof jQuery) {
|
||||||
|
el = el[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
|
return (
|
||||||
|
rect.top >= 0 &&
|
||||||
|
rect.left >= 0 &&
|
||||||
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
|
||||||
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,20 +8,31 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
mod = AIRTIME.library;
|
mod = AIRTIME.library;
|
||||||
|
|
||||||
mod.checkAddButton = function() {
|
mod.checkAddButton = function() {
|
||||||
var selected = mod.getChosenItemsLength(), $cursor = $('tr.cursor-selected-row'), check = false;
|
var selected = mod.getChosenItemsLength(), $cursor = $('tr.sb-selected'), check = false,
|
||||||
|
shows = $('tr.sb-header'), current = $('tr.sb-current-show'),
|
||||||
|
cursorText = $.i18n._('Add to next show');
|
||||||
|
|
||||||
// make sure library items are selected and a cursor is selected.
|
// make sure library items are selected and a cursor is selected.
|
||||||
if (selected !== 0 && $cursor.length !== 0) {
|
if (selected !== 0) {
|
||||||
check = true;
|
check = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shows.length === 0) {
|
||||||
|
check = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (check === true) {
|
if (check === true) {
|
||||||
AIRTIME.button.enableButton("btn-group #library-plus", false);
|
AIRTIME.button.enableButton("btn-group #library-plus", false);
|
||||||
} else {
|
} else {
|
||||||
AIRTIME.button.disableButton("btn-group #library-plus", false);
|
AIRTIME.button.disableButton("btn-group #library-plus", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AIRTIME.library.changeAddButtonText($('.btn-group #library-plus #lib-plus-text'), ' '+$.i18n._('Add to selected show'));
|
if ($cursor.length !== 0) {
|
||||||
|
cursorText = $.i18n._('Add before selected items');
|
||||||
|
} else if (current.length !== 0) {
|
||||||
|
cursorText = $.i18n._('Add to current show');
|
||||||
|
}
|
||||||
|
AIRTIME.library.changeAddButtonText($('.btn-group #library-plus #lib-plus-text'), ' '+ cursorText);
|
||||||
};
|
};
|
||||||
|
|
||||||
mod.fnRowCallback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
|
mod.fnRowCallback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
|
||||||
|
@ -98,7 +109,7 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
"type" : type
|
"type" : type
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show_builder_table tr.cursor-selected-row").each(function(i, el) {
|
$("#show_builder_table tr.sb-selected").each(function(i, el) {
|
||||||
aData.push($(el).prev().data("aData"));
|
aData.push($(el).prev().data("aData"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,12 +124,35 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aSchedIds.length == 0) {
|
if (aSchedIds.length == 0) {
|
||||||
alert($.i18n._("Please select a cursor position on timeline."));
|
addToCurrentOrNext(aSchedIds);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds);
|
AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function addToCurrentOrNext(arr) {
|
||||||
|
var el;
|
||||||
|
// Get the show instance id of the first non-data row (id = 0)
|
||||||
|
// The second last row in the table with that instance id is the
|
||||||
|
// last schedule item for the first show. (This is important for
|
||||||
|
// the Now Playing screen if multiple shows are in view).
|
||||||
|
el = $("[si_id="+$("#0").attr("si_id")+"]");
|
||||||
|
var temp = el.eq(-2).data("aData");
|
||||||
|
arr.push({
|
||||||
|
"id" : temp.id,
|
||||||
|
"instance" : temp.instance,
|
||||||
|
"timestamp" : temp.timestamp
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isInView(el)) {
|
||||||
|
$('.dataTables_scrolling.sb-padded').animate({
|
||||||
|
scrollTop: el.offset().top
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
mod.setupLibraryToolbar = function() {
|
mod.setupLibraryToolbar = function() {
|
||||||
var $toolbar = $(".lib-content .fg-toolbar:first");
|
var $toolbar = $(".lib-content .fg-toolbar:first");
|
||||||
|
|
||||||
|
@ -146,7 +180,7 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#show_builder_table tr.cursor-selected-row")
|
$("#show_builder_table tr.sb-selected")
|
||||||
.each(function(i, el) {
|
.each(function(i, el) {
|
||||||
aData.push($(el).prev().data("aData"));
|
aData.push($(el).prev().data("aData"));
|
||||||
});
|
});
|
||||||
|
@ -161,6 +195,10 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
"timestamp" : temp.timestamp
|
"timestamp" : temp.timestamp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aSchedIds.length == 0) {
|
||||||
|
addToCurrentOrNext(aSchedIds);
|
||||||
|
}
|
||||||
|
|
||||||
AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds);
|
AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds);
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,7 +109,7 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
|
|
||||||
mod.changeAddButtonText = function($button, btnText) {
|
mod.changeAddButtonText = function($button, btnText) {
|
||||||
$button.text(btnText);
|
$button.text(btnText);
|
||||||
}
|
};
|
||||||
|
|
||||||
mod.createToolbarButtons = function() {
|
mod.createToolbarButtons = function() {
|
||||||
$menu = $("<div class='btn-toolbar' />");
|
$menu = $("<div class='btn-toolbar' />");
|
||||||
|
@ -135,7 +135,7 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
"<i class='icon-white icon-trash'></i>" +
|
"<i class='icon-white icon-trash'></i>" +
|
||||||
"</button>" +
|
"</button>" +
|
||||||
"</div>");
|
"</div>");
|
||||||
}
|
};
|
||||||
|
|
||||||
mod.createToolbarDropDown = function() {
|
mod.createToolbarDropDown = function() {
|
||||||
$('#sb-select-page').click(function(){mod.selectCurrentPage();});
|
$('#sb-select-page').click(function(){mod.selectCurrentPage();});
|
||||||
|
@ -530,12 +530,14 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
},
|
},
|
||||||
"fnStateSave": function (oSettings, oData) {
|
"fnStateSave": function (oSettings, oData) {
|
||||||
localStorage.setItem('datatables-library', JSON.stringify(oData));
|
localStorage.setItem('datatables-library', JSON.stringify(oData));
|
||||||
|
/*
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: baseUrl+"usersettings/set-library-datatable",
|
url: baseUrl+"usersettings/set-library-datatable",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {settings : oData, format: "json"},
|
data: {settings : oData, format: "json"},
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
colReorderMap = oData.ColReorder;
|
colReorderMap = oData.ColReorder;
|
||||||
},
|
},
|
||||||
|
@ -890,7 +892,6 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
checkImportStatus();
|
|
||||||
checkLibrarySCUploadStatus();
|
checkLibrarySCUploadStatus();
|
||||||
|
|
||||||
addQtipToSCIcons();
|
addQtipToSCIcons();
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
function showErrorSections() {
|
function showErrorSections() {
|
||||||
if($("#soundcloud-settings .errors").length > 0) {
|
var selector = $("[id$=-settings]");
|
||||||
$("#soundcloud-settings").show();
|
selector.each(function(i) {
|
||||||
$(window).scrollTop($("#soundcloud-settings .errors").position().top);
|
var el = $(this);
|
||||||
}
|
var errors = el.find(".errors");
|
||||||
|
if (errors.length > 0) {
|
||||||
if($("#email-server-settings .errors").length > 0) {
|
el.show();
|
||||||
$("#email-server-settings").show();
|
$(window).scrollTop(errors.position().top);
|
||||||
$(window).scrollTop($("#email-server-settings .errors").position().top);
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if($("#livestream-settings .errors").length > 0) {
|
|
||||||
$("#livestream-settings").show();
|
|
||||||
$(window).scrollTop($("#livestream-settings .errors").position().top);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setConfigureMailServerListener() {
|
function setConfigureMailServerListener() {
|
||||||
|
@ -63,6 +58,30 @@ function setMailServerInputReadonly() {
|
||||||
setMsAuthenticationFieldsReadonly(requiresAuthCB);
|
setMsAuthenticationFieldsReadonly(requiresAuthCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setTuneInSettingsListener() {
|
||||||
|
var enableTunein = $("#enable_tunein");
|
||||||
|
enableTunein.click(function(event){
|
||||||
|
setTuneInSettingsReadonly();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTuneInSettingsReadonly() {
|
||||||
|
var enableTunein = $("#enable_tunein");
|
||||||
|
var stationId = $("#tunein_station_id");
|
||||||
|
var partnerKey = $("#tunein_partner_key");
|
||||||
|
var partnerId = $("#tunein_partner_id");
|
||||||
|
|
||||||
|
if (enableTunein.is(':checked')) {
|
||||||
|
stationId.removeAttr("readonly");
|
||||||
|
partnerKey.removeAttr("readonly");
|
||||||
|
partnerId.removeAttr("readonly");
|
||||||
|
} else {
|
||||||
|
stationId.attr("readonly", "readonly");
|
||||||
|
partnerKey.attr("readonly", "readonly");
|
||||||
|
partnerId.attr("readonly", "readonly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable/disable mail server authentication fields
|
* Enable/disable mail server authentication fields
|
||||||
*/
|
*/
|
||||||
|
@ -120,6 +139,14 @@ function removeLogo() {
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteAllFiles() {
|
||||||
|
var resp = confirm($.i18n._("Are you sure you want to delete all the tracks in your library?"))
|
||||||
|
if (resp) {
|
||||||
|
$.post(baseUrl+'Preference/delete-all-files', function(json){});
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
$('.collapsible-header').live('click',function() {
|
$('.collapsible-header').live('click',function() {
|
||||||
|
@ -128,6 +155,10 @@ $(document).ready(function() {
|
||||||
return false;
|
return false;
|
||||||
}).next().hide();
|
}).next().hide();
|
||||||
|
|
||||||
|
if ($("#tunein-settings").find(".errors").length > 0) {
|
||||||
|
$(".collapsible-content#tunein-settings").show();
|
||||||
|
}
|
||||||
|
|
||||||
/* No longer using AJAX for this form. Zend + our code makes it needlessly hard to deal with. -- Albert
|
/* No longer using AJAX for this form. Zend + our code makes it needlessly hard to deal with. -- Albert
|
||||||
$('#pref_save').live('click', function() {
|
$('#pref_save').live('click', function() {
|
||||||
var data = $('#pref_form').serialize();
|
var data = $('#pref_form').serialize();
|
||||||
|
@ -151,4 +182,6 @@ $(document).ready(function() {
|
||||||
setConfigureMailServerListener();
|
setConfigureMailServerListener();
|
||||||
setEnableSystemEmailsListener();
|
setEnableSystemEmailsListener();
|
||||||
setCollapsibleWidgetJsCode();
|
setCollapsibleWidgetJsCode();
|
||||||
|
setTuneInSettingsReadonly();
|
||||||
|
setTuneInSettingsListener();
|
||||||
});
|
});
|
||||||
|
|
|
@ -360,13 +360,7 @@ function windowResize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function preloadEventFeed () {
|
function preloadEventFeed () {
|
||||||
var url = baseUrl+'Schedule/event-feed-preload';
|
createFullCalendar({calendarInit: calendarPref});
|
||||||
var d = new Date();
|
|
||||||
|
|
||||||
$.post(url, {format: "json", cachep: d.getTime()}, function(json){
|
|
||||||
calendarEvents = json.events;
|
|
||||||
createFullCalendar({calendarInit: calendarPref});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var initialLoad = true;
|
var initialLoad = true;
|
||||||
|
|
|
@ -312,7 +312,7 @@ function createFullCalendar(data){
|
||||||
],
|
],
|
||||||
contentHeight: mainHeight,
|
contentHeight: mainHeight,
|
||||||
theme: true,
|
theme: true,
|
||||||
lazyFetching: false,
|
lazyFetching: true,
|
||||||
serverTimestamp: parseInt(data.calendarInit.timestamp, 10),
|
serverTimestamp: parseInt(data.calendarInit.timestamp, 10),
|
||||||
serverTimezoneOffset: parseInt(data.calendarInit.timezoneOffset, 10),
|
serverTimezoneOffset: parseInt(data.calendarInit.timezoneOffset, 10),
|
||||||
|
|
||||||
|
|
|
@ -278,7 +278,8 @@ var AIRTIME = (function(AIRTIME){
|
||||||
oSchedTable.fnDraw();
|
oSchedTable.fnDraw();
|
||||||
|
|
||||||
mod.enableUI();
|
mod.enableUI();
|
||||||
$("#library_content").find("#library_display").dataTable().fnStandingRedraw();
|
//Unneccessary reload of the library pane after moving tracks in the showbuilder pane.
|
||||||
|
//$("#library_content").find("#library_display").dataTable().fnStandingRedraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
mod.getSelectedCursors = function() {
|
mod.getSelectedCursors = function() {
|
||||||
|
@ -398,13 +399,20 @@ var AIRTIME = (function(AIRTIME){
|
||||||
|
|
||||||
$scroll.scrollTop(currentTop - scrollingTop + scrolled);
|
$scroll.scrollTop(currentTop - scrollingTop + scrolled);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.builderDataTable = function() {
|
mod.builderDataTable = function() {
|
||||||
$sbContent = $('#show_builder');
|
$sbContent = $('#show_builder');
|
||||||
$lib = $("#library_content"),
|
$lib = $("#library_content"),
|
||||||
$sbTable = $sbContent.find('table');
|
$sbTable = $sbContent.find('table');
|
||||||
var isInitialized = false;
|
var isInitialized = false;
|
||||||
|
|
||||||
|
var emptyNode = document.createElement('div');
|
||||||
|
var lockedPreviewIcon = document.createElement('span');
|
||||||
|
lockedPreviewIcon.setAttribute('class', 'ui-icon ui-icon-locked');
|
||||||
|
var previewIcon = document.createElement('img');
|
||||||
|
previewIcon.setAttribute('src', baseUrl+'css/images/icon_audioclip.png');
|
||||||
|
previewIcon.setAttribute('title', $.i18n._("Track preview"));
|
||||||
|
|
||||||
oSchedTable = $sbTable.dataTable( {
|
oSchedTable = $sbTable.dataTable( {
|
||||||
"aoColumns": [
|
"aoColumns": [
|
||||||
/* checkbox */ {"mDataProp": "allowed", "sTitle": "", "sWidth": "15px", "sClass": "sb-checkbox"},
|
/* checkbox */ {"mDataProp": "allowed", "sTitle": "", "sWidth": "15px", "sClass": "sb-checkbox"},
|
||||||
|
@ -429,6 +437,7 @@ var AIRTIME = (function(AIRTIME){
|
||||||
"bServerSide": true,
|
"bServerSide": true,
|
||||||
"bInfo": false,
|
"bInfo": false,
|
||||||
"bAutoWidth": false,
|
"bAutoWidth": false,
|
||||||
|
"bDeferRender": true,
|
||||||
|
|
||||||
"bStateSave": true,
|
"bStateSave": true,
|
||||||
"fnStateSaveParams": function (oSettings, oData) {
|
"fnStateSaveParams": function (oSettings, oData) {
|
||||||
|
@ -439,13 +448,14 @@ var AIRTIME = (function(AIRTIME){
|
||||||
"fnStateSave": function fnStateSave(oSettings, oData) {
|
"fnStateSave": function fnStateSave(oSettings, oData) {
|
||||||
|
|
||||||
localStorage.setItem('datatables-timeline', JSON.stringify(oData));
|
localStorage.setItem('datatables-timeline', JSON.stringify(oData));
|
||||||
|
|
||||||
|
/*
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: baseUrl+"usersettings/set-timeline-datatable",
|
url: baseUrl+"usersettings/set-timeline-datatable",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {settings : oData, format: "json"},
|
data: {settings : oData, format: "json"},
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
});
|
});*/
|
||||||
},
|
},
|
||||||
"fnStateLoad": function fnBuilderStateLoad(oSettings) {
|
"fnStateLoad": function fnBuilderStateLoad(oSettings) {
|
||||||
var settings = localStorage.getItem('datatables-timeline');
|
var settings = localStorage.getItem('datatables-timeline');
|
||||||
|
@ -466,7 +476,8 @@ var AIRTIME = (function(AIRTIME){
|
||||||
a[i] = (a[i] === "true") ? true : false;
|
a[i] = (a[i] === "true") ? true : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
a = oData.ColReorder;
|
a = oData.ColReorder;
|
||||||
if (a) {
|
if (a) {
|
||||||
for (i = 0, length = a.length; i < length; i++) {
|
for (i = 0, length = a.length; i < length; i++) {
|
||||||
|
@ -474,7 +485,7 @@ var AIRTIME = (function(AIRTIME){
|
||||||
a[i] = parseInt(a[i], 10);
|
a[i] = parseInt(a[i], 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
oData.iCreate = parseInt(oData.iCreate, 10);
|
oData.iCreate = parseInt(oData.iCreate, 10);
|
||||||
},
|
},
|
||||||
|
@ -494,8 +505,13 @@ var AIRTIME = (function(AIRTIME){
|
||||||
headerIcon;
|
headerIcon;
|
||||||
|
|
||||||
fnPrepareSeparatorRow = function fnPrepareSeparatorRow(sRowContent, sClass, iNodeIndex) {
|
fnPrepareSeparatorRow = function fnPrepareSeparatorRow(sRowContent, sClass, iNodeIndex) {
|
||||||
|
//Albert:
|
||||||
|
//$(nRow.children[iNodeIndex]).replaceWith(emptyNode);
|
||||||
|
|
||||||
|
|
||||||
$node = $(nRow.children[iNodeIndex]);
|
$node = $(nRow.children[iNodeIndex]);
|
||||||
$node.html(sRowContent);
|
$node.html(sRowContent);
|
||||||
|
|
||||||
$node.attr('colspan',100);
|
$node.attr('colspan',100);
|
||||||
for (i = iNodeIndex + 1, length = nRow.children.length; i < length; i = i+1) {
|
for (i = iNodeIndex + 1, length = nRow.children.length; i < length; i = i+1) {
|
||||||
$node = $(nRow.children[i]);
|
$node = $(nRow.children[i]);
|
||||||
|
@ -504,6 +520,7 @@ var AIRTIME = (function(AIRTIME){
|
||||||
}
|
}
|
||||||
|
|
||||||
$nRow.addClass(sClass);
|
$nRow.addClass(sClass);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (aData.header === true) {
|
if (aData.header === true) {
|
||||||
|
@ -576,7 +593,9 @@ var AIRTIME = (function(AIRTIME){
|
||||||
$nRow.find('td').removeClass();
|
$nRow.find('td').removeClass();
|
||||||
|
|
||||||
$node = $(nRow.children[0]);
|
$node = $(nRow.children[0]);
|
||||||
$node.html('');
|
if ($node) {
|
||||||
|
$node.empty();
|
||||||
|
}
|
||||||
|
|
||||||
sSeparatorHTML = '<span>'+$.i18n._("Show Empty")+'</span>';
|
sSeparatorHTML = '<span>'+$.i18n._("Show Empty")+'</span>';
|
||||||
cl = cl + " sb-empty odd";
|
cl = cl + " sb-empty odd";
|
||||||
|
@ -592,24 +611,32 @@ var AIRTIME = (function(AIRTIME){
|
||||||
|
|
||||||
sSeparatorHTML = '<span>'+$.i18n._("Recording From Line In")+'</span>';
|
sSeparatorHTML = '<span>'+$.i18n._("Recording From Line In")+'</span>';
|
||||||
cl = cl + " sb-record odd";
|
cl = cl + " sb-record odd";
|
||||||
|
|
||||||
fnPrepareSeparatorRow(sSeparatorHTML, cl, 1);
|
fnPrepareSeparatorRow(sSeparatorHTML, cl, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
//add the play function if the file exists on disk.
|
//add the play function if the file exists on disk.
|
||||||
$image = $nRow.find('td.sb-image');
|
$image = $nRow.find('td.sb-image');
|
||||||
|
$image.empty();
|
||||||
//check if the file exists.
|
//check if the file exists.
|
||||||
if (aData.image === true) {
|
if (aData.image === true) {
|
||||||
$nRow.addClass("lib-audio");
|
$nRow.addClass("lib-audio");
|
||||||
if (!isAudioSupported(aData.mime)) {
|
if (!isAudioSupported(aData.mime)) {
|
||||||
$image.html('<span class="ui-icon ui-icon-locked"></span>');
|
//$image.html('<span class="ui-icon ui-icon-locked"></span>');
|
||||||
|
$image.append(lockedPreviewIcon);
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
$image.html('<img title="'+$.i18n._("Track preview")+'" src="'+baseUrl+'css/images/icon_audioclip.png"></img>')
|
$image.html('<img title="'+$.i18n._("Track preview")+'" src="'+baseUrl+'css/images/icon_audioclip.png"></img>')
|
||||||
.click(function() {
|
.click(function() {
|
||||||
open_show_preview(aData.instance, aData.pos);
|
open_show_preview(aData.instance, aData.pos);
|
||||||
return false;
|
return false;
|
||||||
|
});*/
|
||||||
|
$image.append(previewIcon.cloneNode(false));
|
||||||
|
$image.click(function() {
|
||||||
|
open_show_preview(aData.instance, aData.pos);
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -625,13 +652,13 @@ var AIRTIME = (function(AIRTIME){
|
||||||
hide: 'mouseout'
|
hide: 'mouseout'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$node = $(nRow.children[0]);
|
$node = $(nRow.children[0]);
|
||||||
if (aData.allowed === true && aData.scheduled >= 1 && aData.linked_allowed) {
|
if (aData.allowed === true && aData.scheduled >= 1 && aData.linked_allowed) {
|
||||||
$node.html('<input type="checkbox" name="'+aData.id+'"></input>');
|
$node.html('<input type="checkbox" name="'+aData.id+'"></input>');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$node.html('');
|
$node.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +732,6 @@ var AIRTIME = (function(AIRTIME){
|
||||||
$("#draggingContainer").remove();
|
$("#draggingContainer").remove();
|
||||||
},
|
},
|
||||||
"fnDrawCallback": function fnBuilderDrawCallback(oSettings, json) {
|
"fnDrawCallback": function fnBuilderDrawCallback(oSettings, json) {
|
||||||
var isInitialized = false;
|
|
||||||
|
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
//when coming to 'Now Playing' page we want the page
|
//when coming to 'Now Playing' page we want the page
|
||||||
|
@ -730,7 +756,8 @@ var AIRTIME = (function(AIRTIME){
|
||||||
heights = [];
|
heights = [];
|
||||||
|
|
||||||
clearTimeout(mod.timeout);
|
clearTimeout(mod.timeout);
|
||||||
|
|
||||||
|
/*
|
||||||
//only create the cursor arrows if the library is on the page.
|
//only create the cursor arrows if the library is on the page.
|
||||||
if ($lib.length > 0 && $lib.filter(":visible").length > 0) {
|
if ($lib.length > 0 && $lib.filter(":visible").length > 0) {
|
||||||
|
|
||||||
|
@ -775,18 +802,18 @@ var AIRTIME = (function(AIRTIME){
|
||||||
$tr = $table.find("tr[id="+cursorIds[i]+"][si_id="+showInstanceIds[i]+"]");
|
$tr = $table.find("tr[id="+cursorIds[i]+"][si_id="+showInstanceIds[i]+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the currently playing track's cursor is selected,
|
//If the currently playing track's cursor is selected,
|
||||||
* and that track is deleted, the cursor position becomes
|
//and that track is deleted, the cursor position becomes
|
||||||
* unavailble. We have to check the position is available
|
//unavailble. We have to check the position is available
|
||||||
* before re-highlighting it.
|
// before re-highlighting it.
|
||||||
*/
|
//
|
||||||
if ($tr.find(".sb-checkbox").children().hasClass("innerWrapper")) {
|
if ($tr.find(".sb-checkbox").children().hasClass("innerWrapper")) {
|
||||||
mod.selectCursor($tr);
|
mod.selectCursor($tr);
|
||||||
|
|
||||||
/* If the selected cursor is the footer row we need to
|
// If the selected cursor is the footer row we need to
|
||||||
* explicitly select it because that row does not have
|
//explicitly select it because that row does not have
|
||||||
* innerWrapper class
|
// innerWrapper class
|
||||||
*/
|
//
|
||||||
} else if ($tr.hasClass("sb-footer")) {
|
} else if ($tr.hasClass("sb-footer")) {
|
||||||
mod.selectCursor($tr);
|
mod.selectCursor($tr);
|
||||||
}
|
}
|
||||||
|
@ -801,8 +828,9 @@ var AIRTIME = (function(AIRTIME){
|
||||||
}
|
}
|
||||||
|
|
||||||
$parent.append($table);
|
$parent.append($table);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
//order of importance of elements for setting the next timeout.
|
//order of importance of elements for setting the next timeout.
|
||||||
elements = [
|
elements = [
|
||||||
$sbTable.find("tr."+NOW_PLAYING_CLASS),
|
$sbTable.find("tr."+NOW_PLAYING_CLASS),
|
||||||
|
@ -826,6 +854,7 @@ var AIRTIME = (function(AIRTIME){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mod.checkToolBarIcons();
|
mod.checkToolBarIcons();
|
||||||
},
|
},
|
||||||
|
@ -957,9 +986,9 @@ var AIRTIME = (function(AIRTIME){
|
||||||
//item was reordered.
|
//item was reordered.
|
||||||
else {
|
else {
|
||||||
|
|
||||||
ui.item
|
//ui.item
|
||||||
.empty()
|
// .empty()
|
||||||
.after(draggingContainer.html());
|
// .after(draggingContainer.html());
|
||||||
|
|
||||||
aItemData.push(ui.item.data("aData"));
|
aItemData.push(ui.item.data("aData"));
|
||||||
fnMove();
|
fnMove();
|
||||||
|
@ -968,9 +997,10 @@ var AIRTIME = (function(AIRTIME){
|
||||||
|
|
||||||
return {
|
return {
|
||||||
placeholder: "sb-placeholder ui-state-highlight",
|
placeholder: "sb-placeholder ui-state-highlight",
|
||||||
forcePlaceholderSize: true,
|
//forcePlaceholderSize: true,
|
||||||
distance: 10,
|
distance: 10,
|
||||||
helper: function(event, item) {
|
helper:
|
||||||
|
function(event, item) {
|
||||||
var selected = mod.getSelectedData(NOW_PLAYING_CLASS),
|
var selected = mod.getSelectedData(NOW_PLAYING_CLASS),
|
||||||
thead = $("#show_builder_table thead"),
|
thead = $("#show_builder_table thead"),
|
||||||
colspan = thead.find("th").length,
|
colspan = thead.find("th").length,
|
||||||
|
@ -985,23 +1015,34 @@ var AIRTIME = (function(AIRTIME){
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.length === 1) {
|
if (selected.length === 1) {
|
||||||
message = $.i18n._("Moving 1 Item");
|
message = sprintf($.i18n._("Moving %s"), selected[0].title);
|
||||||
}
|
//draggingContainer = item; //Default DataTables drag and drop
|
||||||
else {
|
draggingContainer = $('<tr/>')
|
||||||
message = sprintf($.i18n._("Moving %s Items"), selected.length);
|
.addClass('sb-helper')
|
||||||
}
|
.append('<td/>')
|
||||||
|
.find("td")
|
||||||
draggingContainer = $('<tr/>')
|
|
||||||
.addClass('sb-helper')
|
|
||||||
.append('<td/>')
|
|
||||||
.find("td")
|
|
||||||
.attr("colspan", colspan)
|
.attr("colspan", colspan)
|
||||||
.width(width)
|
.width(width)
|
||||||
.height(height)
|
.height(height)
|
||||||
.addClass("ui-state-highlight")
|
.addClass("ui-state-highlight")
|
||||||
.append(message)
|
.append(message)
|
||||||
.end();
|
.end();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = sprintf($.i18n._("Moving %s Items"), selected.length);
|
||||||
|
draggingContainer = $('<tr/>')
|
||||||
|
.addClass('sb-helper')
|
||||||
|
.append('<td/>')
|
||||||
|
.find("td")
|
||||||
|
.attr("colspan", colspan)
|
||||||
|
.width(width)
|
||||||
|
.height(height)
|
||||||
|
.addClass("ui-state-highlight")
|
||||||
|
.append(message)
|
||||||
|
.end();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
helperData = selected;
|
helperData = selected;
|
||||||
|
|
||||||
return draggingContainer;
|
return draggingContainer;
|
||||||
|
|
|
@ -168,7 +168,7 @@ AIRTIME = (function(AIRTIME) {
|
||||||
$builder.find(dateStartId)
|
$builder.find(dateStartId)
|
||||||
.datepicker(oBaseDatePickerSettings)
|
.datepicker(oBaseDatePickerSettings)
|
||||||
.blur(validateTimeRange);
|
.blur(validateTimeRange);
|
||||||
|
|
||||||
$builder.find(timeStartId)
|
$builder.find(timeStartId)
|
||||||
.timepicker(oBaseTimePickerSettings)
|
.timepicker(oBaseTimePickerSettings)
|
||||||
.blur(validateTimeRange);
|
.blur(validateTimeRange);
|
||||||
|
@ -328,10 +328,10 @@ AIRTIME = (function(AIRTIME) {
|
||||||
setTimeout(checkScheduleUpdates, 5000);
|
setTimeout(checkScheduleUpdates, 5000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
//check if the timeline view needs updating.
|
//check if the timeline view needs updating.
|
||||||
checkScheduleUpdates();
|
setTimeout(checkScheduleUpdates, 5000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mod.onResize = function() {
|
mod.onResize = function() {
|
||||||
|
|
|
@ -3,16 +3,14 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import collections
|
import collections
|
||||||
import Queue
|
import Queue
|
||||||
import subprocess
|
|
||||||
import multiprocessing
|
|
||||||
import time
|
import time
|
||||||
import sys
|
|
||||||
import traceback
|
import traceback
|
||||||
import os
|
|
||||||
import pickle
|
import pickle
|
||||||
import threading
|
import threading
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
|
||||||
class PicklableHttpRequest:
|
class PicklableHttpRequest:
|
||||||
def __init__(self, method, url, data, api_key):
|
def __init__(self, method, url, data, api_key):
|
||||||
self.method = method
|
self.method = method
|
||||||
|
@ -158,23 +156,23 @@ class StatusReporter():
|
||||||
''' We use multiprocessing.Process again here because we need a thread for this stuff
|
''' We use multiprocessing.Process again here because we need a thread for this stuff
|
||||||
anyways, and Python gives us process isolation for free (crash safety).
|
anyways, and Python gives us process isolation for free (crash safety).
|
||||||
'''
|
'''
|
||||||
_ipc_queue = multiprocessing.Queue()
|
_ipc_queue = Queue.Queue()
|
||||||
#_request_process = multiprocessing.Process(target=process_http_requests,
|
#_http_thread = multiprocessing.Process(target=process_http_requests,
|
||||||
# args=(_ipc_queue,))
|
# args=(_ipc_queue,))
|
||||||
_request_process = None
|
_http_thread = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def start_thread(self, http_retry_queue_path):
|
def start_thread(self, http_retry_queue_path):
|
||||||
StatusReporter._request_process = threading.Thread(target=process_http_requests,
|
StatusReporter._http_thread = threading.Thread(target=process_http_requests,
|
||||||
args=(StatusReporter._ipc_queue,http_retry_queue_path))
|
args=(StatusReporter._ipc_queue,http_retry_queue_path))
|
||||||
StatusReporter._request_process.start()
|
StatusReporter._http_thread.start()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def stop_thread(self):
|
def stop_thread(self):
|
||||||
logging.info("Terminating status_reporter process")
|
logging.info("Terminating status_reporter process")
|
||||||
#StatusReporter._request_process.terminate() # Triggers SIGTERM on the child process
|
#StatusReporter._http_thread.terminate() # Triggers SIGTERM on the child process
|
||||||
StatusReporter._ipc_queue.put("shutdown") # Special trigger
|
StatusReporter._ipc_queue.put("shutdown") # Special trigger
|
||||||
StatusReporter._request_process.join()
|
StatusReporter._http_thread.join()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _send_http_request(self, request):
|
def _send_http_request(self, request):
|
||||||
|
|
|
@ -23,12 +23,13 @@ setup(name='airtime_analyzer',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'mutagen',
|
'mutagen',
|
||||||
'pika',
|
'pika',
|
||||||
|
'daemon',
|
||||||
'python-magic',
|
'python-magic',
|
||||||
'nose',
|
'nose',
|
||||||
'coverage',
|
'coverage',
|
||||||
'mock',
|
'mock',
|
||||||
'python-daemon==1.6',
|
'python-daemon==1.6',
|
||||||
'requests',
|
'requests>=2.7.0',
|
||||||
'apache-libcloud',
|
'apache-libcloud',
|
||||||
'rgain',
|
'rgain',
|
||||||
'boto',
|
'boto',
|
||||||
|
|
|
@ -83,6 +83,7 @@ api_config['push_stream_stats'] = 'push-stream-stats/api_key/%%api_key%%/format/
|
||||||
api_config['update_stream_setting_table'] = 'update-stream-setting-table/api_key/%%api_key%%/format/json'
|
api_config['update_stream_setting_table'] = 'update-stream-setting-table/api_key/%%api_key%%/format/json'
|
||||||
api_config['get_files_without_silan_value'] = 'get-files-without-silan-value/api_key/%%api_key%%'
|
api_config['get_files_without_silan_value'] = 'get-files-without-silan-value/api_key/%%api_key%%'
|
||||||
api_config['update_cue_values_by_silan'] = 'update-cue-values-by-silan/api_key/%%api_key%%'
|
api_config['update_cue_values_by_silan'] = 'update-cue-values-by-silan/api_key/%%api_key%%'
|
||||||
|
api_config['update_metadata_on_tunein'] = 'update-metadata-on-tunein/api_key/%%api_key%%'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -530,6 +531,9 @@ class AirtimeApiClient(object):
|
||||||
#TODO
|
#TODO
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
|
|
||||||
|
def update_metadata_on_tunein(self):
|
||||||
|
self.services.update_metadata_on_tunein()
|
||||||
|
|
||||||
|
|
||||||
class InvalidContentType(Exception):
|
class InvalidContentType(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -14,7 +14,7 @@ import traceback
|
||||||
import pure
|
import pure
|
||||||
|
|
||||||
from Queue import Empty
|
from Queue import Empty
|
||||||
from threading import Thread
|
from threading import Thread, Timer
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
from api_clients import api_client
|
from api_clients import api_client
|
||||||
|
@ -447,6 +447,12 @@ class PypoFetch(Thread):
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
# This function makes a request to Airtime to see if we need to
|
||||||
|
# push metadata to TuneIn. We have to do this because TuneIn turns
|
||||||
|
# off metadata if it does not receive a request every 5 minutes.
|
||||||
|
def update_metadata_on_tunein(self):
|
||||||
|
self.api_client.update_metadata_on_tunein()
|
||||||
|
Timer(120, self.update_metadata_on_tunein).start()
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
#Make sure all Liquidsoap queues are empty. This is important in the
|
#Make sure all Liquidsoap queues are empty. This is important in the
|
||||||
|
@ -458,8 +464,10 @@ class PypoFetch(Thread):
|
||||||
|
|
||||||
self.set_bootstrap_variables()
|
self.set_bootstrap_variables()
|
||||||
|
|
||||||
|
self.update_metadata_on_tunein()
|
||||||
|
|
||||||
# Bootstrap: since we are just starting up, we need to grab the
|
# Bootstrap: since we are just starting up, we need to grab the
|
||||||
# most recent schedule. After that we fetch the schedule every 30
|
# most recent schedule. After that we fetch the schedule every 8
|
||||||
# minutes or wait for schedule updates to get pushed.
|
# minutes or wait for schedule updates to get pushed.
|
||||||
success = self.persistent_manual_schedule_fetch(max_attempts=5)
|
success = self.persistent_manual_schedule_fetch(max_attempts=5)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue