Merge branch 'saas-dev' into saas-speedy

This commit is contained in:
Duncan Sommerville 2015-05-04 13:09:51 -04:00
commit 8b380086c3
32 changed files with 4981 additions and 1287 deletions

View file

@ -78,9 +78,9 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$view->headScript()->appendScript("var baseUrl = '$baseUrl';");
$this->_initTranslationGlobals($view);
$user = Application_Model_User::GetCurrentUser();
if (!is_null($user)){
if (!is_null($user)) {
$userType = $user->getType();
} else {
$userType = "";
@ -91,14 +91,15 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
/**
* Create a global namespace to hold a session token for CSRF prevention
*/
protected function _initCsrfNamespace() {
protected function _initCsrfNamespace()
{
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
// Check if the token exists
if (!$csrf_namespace->authtoken) {
// If we don't have a token, regenerate it and set a 2 hour timeout
// Should we log the user out here if the token is expired?
$csrf_namespace->authtoken = sha1(uniqid(rand(),1));
$csrf_namespace->setExpirationSeconds(2*60*60);
$csrf_namespace->authtoken = sha1(uniqid(rand(), 1));
$csrf_namespace->setExpirationSeconds(2 * 60 * 60);
}
//Here we are closing the session for writing because otherwise no requests
@ -106,13 +107,14 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
//of the application (page load times are more consistent, no lock contention).
session_write_close();
}
/**
* Ideally, globals should be written to a single js file once
* from a php init function. This will save us from having to
* Ideally, globals should be written to a single js file once
* from a php init function. This will save us from having to
* reinitialize them every request
*/
private function _initTranslationGlobals() {
private function _initTranslationGlobals()
{
$view = $this->getResource('view');
$view->headScript()->appendScript("var PRODUCT_NAME = '" . PRODUCT_NAME . "';");
$view->headScript()->appendScript("var USER_MANUAL_URL = '" . USER_MANUAL_URL . "';");
@ -127,13 +129,13 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$baseUrl = Application_Common_OsPath::getBaseDir();
$view->headLink()->appendStylesheet($baseUrl.'css/bootstrap.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/redmond/jquery-ui-1.8.8.custom.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/pro_dropdown_3.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/qtip/jquery.qtip.min.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/styles.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/masterpanel.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl.'css/tipsy/jquery.tipsy.css?'.$CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/bootstrap.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/redmond/jquery-ui-1.8.8.custom.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/pro_dropdown_3.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/qtip/jquery.qtip.min.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/styles.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/masterpanel.css?' . $CC_CONFIG['airtime_version']);
$view->headLink()->appendStylesheet($baseUrl . 'css/tipsy/jquery.tipsy.css?' . $CC_CONFIG['airtime_version']);
}
protected function _initHeadScript()
@ -144,72 +146,73 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$baseUrl = Application_Common_OsPath::getBaseDir();
$view->headScript()->appendFile($baseUrl.'js/libs/jquery-1.8.3.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/libs/jquery-ui-1.8.24.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/bootstrap/bootstrap.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/libs/jquery-1.8.3.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/libs/jquery-ui-1.8.24.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/bootstrap/bootstrap.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/libs/underscore-min.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/libs/underscore-min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/libs/jquery.stickyPanel.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/qtip/jquery.qtip.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/jplayer/jquery.jplayer.min.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/sprintf/sprintf-0.7-beta1.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/cookie/jquery.cookie.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/i18n/jquery.i18n.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'locale/general-translation-table?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'locale/datatables-translation-table?'.$CC_CONFIG['airtime_version'],'text/javascript');
// $view->headScript()->appendFile($baseUrl . 'js/libs/jquery.stickyPanel.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/qtip/jquery.qtip.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/jplayer/jquery.jplayer.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/sprintf/sprintf-0.7-beta1.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/cookie/jquery.cookie.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/i18n/jquery.i18n.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'locale/general-translation-table?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'locale/datatables-translation-table?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendScript("$.i18n.setDictionary(general_dict)");
$view->headScript()->appendScript("var baseUrl='$baseUrl'");
//These timezones are needed to adjust javascript Date objects on the client to make sense to the user's set timezone
//or the server's set timezone.
//These timezones are needed to adjust javascript Date objects on the client to make sense to the user's set timezone
//or the server's set timezone.
$serverTimeZone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone());
$now = new DateTime("now", $serverTimeZone);
$offset = $now->format("Z") * -1;
$view->headScript()->appendScript("var serverTimezoneOffset = {$offset}; //in seconds");
if (class_exists("Zend_Auth", false) && Zend_Auth::getInstance()->hasIdentity()) {
$userTimeZone = new DateTimeZone(Application_Model_Preference::GetUserTimezone());
$now = new DateTime("now", $userTimeZone);
$offset = $now->format("Z") * -1;
$view->headScript()->appendScript("var userTimezoneOffset = {$offset}; //in seconds");
}
//scripts for now playing bar
$view->headScript()->appendFile($baseUrl.'js/airtime/airtime_bootstrap.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/airtime/dashboard/helperfunctions.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/airtime/dashboard/dashboard.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/airtime/dashboard/versiontooltip.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/tipsy/jquery.tipsy.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/airtime/common/common.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'js/airtime/common/audioplaytest.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
if (class_exists("Zend_Auth", false) && Zend_Auth::getInstance()->hasIdentity()) {
$userTimeZone = new DateTimeZone(Application_Model_Preference::GetUserTimezone());
$now = new DateTime("now", $userTimeZone);
$offset = $now->format("Z") * -1;
$view->headScript()->appendScript("var userTimezoneOffset = {$offset}; //in seconds");
}
//scripts for now playing bar
$view->headScript()->appendFile($baseUrl . 'js/airtime/airtime_bootstrap.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/airtime/dashboard/helperfunctions.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/airtime/dashboard/dashboard.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/airtime/dashboard/versiontooltip.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/tipsy/jquery.tipsy.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/airtime/common/common.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl . 'js/airtime/common/audioplaytest.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
$user = Application_Model_User::getCurrentUser();
if (!is_null($user)){
if (!is_null($user)) {
$userType = $user->getType();
} else {
$userType = "";
}
$view->headScript()->appendScript("var userType = '$userType';");
if (array_key_exists('REQUEST_URI', $_SERVER)) { //Doesn't exist for unit tests
if (strpos($_SERVER['REQUEST_URI'], $baseUrl.'Dashboard/stream-player') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl.'audiopreview/audio-preview') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl.'audiopreview/playlist-preview') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl.'audiopreview/block-preview') === false) {
if (strpos($_SERVER['REQUEST_URI'], $baseUrl . 'Dashboard/stream-player') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl . 'audiopreview/audio-preview') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl . 'audiopreview/playlist-preview') === false
&& strpos($_SERVER['REQUEST_URI'], $baseUrl . 'audiopreview/block-preview') === false
) {
$plan_level = strval(Application_Model_Preference::GetPlanLevel());
// Since the Hobbyist plan doesn't come with Live Chat support, don't enable it
if (Application_Model_Preference::GetLiveChatEnabled() && $plan_level !== 'hobbyist') {
$client_id = strval(Application_Model_Preference::GetClientId());
$station_url = $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
$view->headScript()->appendScript("var livechat_client_id = '$client_id';\n".
"var livechat_plan_type = '$plan_level';\n".
"var livechat_station_url = 'http://$station_url';");
$view->headScript()->appendFile($baseUrl . 'js/airtime/common/livechat.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendScript("var livechat_client_id = '$client_id';\n" .
"var livechat_plan_type = '$plan_level';\n" .
"var livechat_station_url = 'http://$station_url';");
$view->headScript()->appendFile($baseUrl . 'js/airtime/common/livechat.js?' . $CC_CONFIG['airtime_version'], 'text/javascript');
}
}
}
}
/*
@ -222,6 +225,8 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
$view = $this->getResource('view');
$view->addHelperPath('../application/views/helpers', 'Airtime_View_Helper');
$view->assign('suspended', (Application_Model_Preference::getProvisioningStatus() == PROVISIONING_STATUS_SUSPENDED));
}
protected function _initTitle()
@ -260,7 +265,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$front->setBaseUrl(Application_Common_OsPath::getBaseDir());
$router->addRoute(
'password-change',
new Zend_Controller_Router_Route('password-change/:user_id/:token', array(

View file

@ -11,7 +11,7 @@ define('COMPANY_SITE_URL' , 'http://sourcefabric.org/');
define('WHOS_USING_URL' , 'http://sourcefabric.org/en/airtime/whosusing');
define('TERMS_AND_CONDITIONS_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_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.html');
@ -87,4 +87,8 @@ define("WHMCS_API_URL", "https://account.sourcefabric.com/includes/api.php");
define("SUBDOMAIN_WHMCS_CUSTOM_FIELD_NAME", "Choose your domain");
//Sentry error logging
define('SENTRY_CONFIG_PATH', '/etc/airtime-saas/sentry.airtime_web.ini');
define('SENTRY_CONFIG_PATH', '/etc/airtime-saas/sentry.airtime_web.ini');
//Provisioning status
define('PROVISIONING_STATUS_SUSPENDED' , 'Suspended');
define('PROVISIONING_STATUS_ACTIVE' , 'Active');

View file

@ -134,7 +134,7 @@ $pages = array(
),
array(
'label' => _('User Manual'),
'uri' => "http://sourcefabric.booktype.pro/airtime-25-for-broadcasters/",
'uri' => "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters",
'target' => "_blank"
),
array(

View file

@ -13,7 +13,6 @@ class DashboardController extends Zend_Controller_Action
public function indexAction()
{
// action body
}
public function disconnectSourceAction()

View file

@ -32,12 +32,15 @@ class ProvisioningController extends Zend_Controller_Action
try {
// This is hacky and should be genericized
if ($_POST['station_name']) {
if (isset($_POST['station_name'])) {
Application_Model_Preference::SetStationName($_POST['station_name']);
}
if ($_POST['description']) {
if (isset($_POST['description'])) {
Application_Model_Preference::SetStationDescription($_POST['description']);
}
if (isset($_POST['provisioning_status'])) {
Application_Model_Preference::setProvisioningStatus($_POST['provisioning_status']);
}
} catch (Exception $e) {
$this->getResponse()
->setHttpResponseCode(400)

View file

@ -20,7 +20,12 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
<!-- End Google Tag Manager -->
<?php echo $this->partial('partialviews/trialBox.phtml', array("is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<div id="Panel">
<div id="Panel" class="sticky">
<?php if($this->suspended) : ?>
<?php echo $this->partial('partialviews/suspended.phtml'); ?>
<?php else : ?>
<?php echo $this->versionNotify();
$sss = $this->SourceSwitchStatus();
$scs = $this->SourceConnectionStatus();
@ -61,8 +66,10 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
<?php echo $this->navigation()->menu() ?>
<div style="clear:both;"></div>
</div>
<?php endif; //suspended ?>
</div>
<div class="wrapper" id="content"><?php echo $this->layout()->content ?></div>
<script id="tmpl-pl-cues" type="text/template">

View file

@ -1441,4 +1441,16 @@ class Application_Model_Preference
self::setDiskUsage($currentDiskUsage + $filesize);
}
public static function setProvisioningStatus($status)
{
//See constants.php for the list of valid values. eg. PROVISIONING_STATUS_ACTIVE
self::setValue("provisioning_status", $status);
}
public static function getProvisioningStatus()
{
return self::getValue("provisioning_status");
}
}

View file

@ -64,13 +64,6 @@ SQL;
{
//Everything in this function must be done in UTC. You will get a swift kick in the pants if you mess that up.
if (!is_int($p_prev) || !is_int($p_next)) {
//must enter integers to specify ranges
Logging::info("Invalid range parameters: $p_prev or $p_next");
return array();
}
// when timeEnd is unspecified, return to the default behaviour - set a range of 48 hours from current time
if (!$utcTimeEnd) {
$end = new DateTime();

View file

@ -150,23 +150,27 @@ class Application_Service_CalendarService
$menu["edit"] = array(
"name" => _("Edit This Instance"),
"icon" => "edit",
"url" => $baseUrl."Schedule/populate-repeating-show-instance-form");
"url" => $baseUrl . "Schedule/populate-repeating-show-instance-form"
);
} else {
$menu["edit"] = array(
"name" => _("Edit"),
"icon" => "edit",
"items" => array());
"items" => array()
);
$menu["edit"]["items"]["all"] = array(
"name" => _("Edit Show"),
"icon" => "edit",
"url" => $baseUrl."Schedule/populate-show-form");
"url" => $baseUrl . "Schedule/populate-show-form"
);
$menu["edit"]["items"]["instance"] = array(
"name" => _("Edit This Instance"),
"icon" => "edit",
"url" => $baseUrl."Schedule/populate-repeating-show-instance-form");
}
"url" => $baseUrl . "Schedule/populate-repeating-show-instance-form"
);
}
} else {
$menu["edit"] = array(
"name"=> _("Edit Show"),

View file

@ -153,14 +153,19 @@ class Application_Service_ShowFormService
if ($ccShowDay->isShowStartInPast()) {
//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
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();
} else {
list($showStart, $showEnd) = $this->getNextFutureRepeatShowTime();
if ($this->hasShowStarted($showStart)) {
$form->disableStartDateAndTime();
}
}
}*/
}
$form->populate(
@ -410,9 +415,8 @@ class Application_Service_ShowFormService
//if the show is repeating, set the start date to the next
//repeating instance in the future
if ($this->ccShow->isRepeating()) {
list($originalShowStartDateTime,) = $this->getNextFutureRepeatShowTime();
} else {
$originalShowStartDateTime = $this->getCurrentOrNextInstanceStartTime();
if (!$originalShowStartDateTime) {
$originalShowStartDateTime = $dt;
}
@ -421,26 +425,30 @@ class Application_Service_ShowFormService
/**
*
* Returns 2 DateTime objects, in the user's local time,
* of the next future repeat show instance start and end time
* Returns a DateTime object, in the user's local 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()
->filterByDbShowId($this->ccShow->getDbId())
->filterByDbModifiedInstance(false)
->filterByDbStarts(gmdate("Y-m-d H:i:s"), Criteria::GREATER_THAN)
->filterByDbStarts(gmdate("Y-m-d"), Criteria::GREATER_EQUAL)
->orderByDbStarts()
->findOne();
if (!$ccShowInstance) {
return null;
}
$starts = new DateTime($ccShowInstance->getDbStarts(), new DateTimeZone("UTC"));
$ends = new DateTime($ccShowInstance->getDbEnds(), new DateTimeZone("UTC"));
$showTimezone = $this->ccShow->getFirstCcShowDay()->getDbTimezone();
$starts->setTimezone(new DateTimeZone($showTimezone));
$ends->setTimezone(new DateTimeZone($showTimezone));
return array($starts, $ends);
return $starts;
}

View file

@ -238,8 +238,8 @@
}
// variables for updating the player's metadata
var time_to_next_track_starts;
var metadataTimer;
var time_to_next_track_starts = 0;
var metadataTimer = null;
// Fetches the streams metadata from the Airtime live-info API
// and attaches it to the player UI.
@ -252,7 +252,12 @@
success: function(data) {
if (data.current === null) {
$("p.now_playing").html("Offline");
if (data.currentShow != null && data.currentShow.length != 0) {
// Master/show source have no current track but they do have a current show.
$("p.now_playing").html(data.currentShow[0].name);
} else {
$("p.now_playing").html("Offline");
}
time_to_next_track_starts = 20000;
} else {
var artist = data.current.name.split(" - ")[0];
@ -260,6 +265,12 @@
$("p.now_playing").html(artist + "<span>" + track + "</span>");
var current_track_end_time = new Date(data.current.ends);
if (current_track_end_time == "Invalid Date" || isNaN(current_track_end_time)) {
// If the conversion didn't work (since the String is not in ISO format)
// then change it to be ISO-compliant. This is somewhat hacky and may break
// if the date string format in live-info changes!
current_track_end_time = new Date((data.current.ends).replace(" ", "T"));
}
var current_time = new Date();
//convert current_time to UTC to match the timezone of time_to_next_track_starts
current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset() * 60 * 1000);
@ -271,9 +282,14 @@
} else {
$("ul.schedule_list").find("li").html(data.next.name);
}
}
});
//Preventative code if the local and remote clocks are out of sync.
if (isNaN(time_to_next_track_starts) || time_to_next_track_starts < 0) {
time_to_next_track_starts = 0;
}
// Add 3 seconds to the timeout so Airtime has time to update the metadata before we fetch it
metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts+3000);
}

View file

@ -23,6 +23,30 @@
<?php //echo $this->element->getElement('player_display_track_metadata'); ?>
<table id="player_compatibility_chart">
<th colspan="5">Stream Compatibility</th>
<tr>
<td colspan="3">Desktop</td>
<td colspan="2">Mobile</td>
</tr>
<tr>
<td>Firefox</td>
<td>Chrome</td>
<td>Internet Explorer</td>
<td>Android 5 - Chrome</td>
<td>iOS 7 - Safari</td>
</tr>
<tr>
<td>Yes (Flash)</td>
<td>Yes (Flash)</td>
<td>Yes (Flash)</td>
<td>MP3/OGG* only</td>
<td>MP3/AAC only</td>
</tr>
<tr>
<td colspan="5">* Chrome on Android is known to take about 4 seconds to buffer a 128 kbps MP3 stream. Lower bitrates take longer to buffer.</td>
</tr>
</table>
</dl>

View file

@ -0,0 +1,9 @@
<div class="suspension_notice">
<H2>Station Suspended</H2>
<p>
<?php echo(_pro(sprintf('Your station is suspended due to an <b>unpaid invoice</b>. To restore your station, <a href="%s">please pay any overdue invoices</a>.', '/billing/invoices'))); ?>
</p>
<p>
<?php echo(_pro(sprintf('Suspended stations will be <b>removed</b> if an invoice is unpaid for 30 days. If you believe this suspension was in error, <a href="%s">please contact support</a>.', 'https://sourcefabricberlin.zendesk.com/anonymous_requests/new'))); ?>
</p>
</div>

View file

@ -5,7 +5,10 @@
</style>
<?php if ($this->quotaLimitReached) { ?>
<div class="errors quota-reached">
Disk quota exceeded. You cannot upload files until you <a href="http://www.sourcefabric.org/en/airtime" target="_blank">upgrade your storage</a>.
Disk quota exceeded. You cannot upload files until you
<a target="_parent" href=<?php $baseUrl = Application_Common_OsPath::getBaseDir(); echo $baseUrl . "billing/upgrade"?>>
upgrade your storage
</a>.
</div>
<?php
}