Merge branch 'master' into feature/analyzer-on-travis

# Conflicts:
#	.travis.yml
This commit is contained in:
Lucas Bickel 2017-03-04 16:35:11 +01:00
commit 188c127057
31 changed files with 372 additions and 199 deletions

View File

@ -55,6 +55,7 @@ install:
fi fi
- > - >
if [[ "$PYTHON" == true ]]; then if [[ "$PYTHON" == true ]]; then
pip install --user mkdocs
pushd python_apps/airtime_analyzer pushd python_apps/airtime_analyzer
python setup.py install --dry-run --no-init-script python setup.py install --dry-run --no-init-script
popd popd
@ -69,3 +70,17 @@ before_script:
script: script:
- ./travis/php.sh - ./travis/php.sh
- ./travis/python.sh - ./travis/python.sh
- mkdocs build --clean -q > /dev/null
deploy:
provider: pages
skip_cleanup: true
local_dir: build/docs
github_token: $GITHUB_TOKEN # Set in travis-ci.org dashboard
target_branch: master
repo: LibreTime/LibreTime.github.io
project_name: LibreTime
fqdn: libretime.org
name: R. LibreTime DocBot
on:
branch: master
env: PYTHON=true

View File

@ -118,8 +118,14 @@ class Amazon_S3StorageBackend extends StorageBackend
public function getFilePrefix() public function getFilePrefix()
{ {
$hostingId = Billing::getClientInstanceId(); $filePrefix = '';
$filePrefix = substr($hostingId, -2)."/".$hostingId; // only prefix files on S3 when billing is active since saas customers share a s3 bucket
// I'm not sure why the choice was made to put everything into one bucket
// We might refactor this to use a bucket per customer if we revisit S3
if (LIBRETIME_ENABLE_BILLING === true) {
$hostingId = Billing::getClientInstanceId();
$filePrefix = substr($hostingId, -2)."/".$hostingId;
}
return $filePrefix; return $filePrefix;
} }
} }

View File

@ -103,7 +103,7 @@ class Application_Common_UsabilityHints
"<a href=\"/schedule\">", "<a href=\"/schedule\">",
"</a>"); "</a>");
} }
} else if ($userIsOnShowbuilderPage && $userIsSuperAdmin) { } else if (LIBRETIME_ENABLE_BILLING === true && $userIsOnShowbuilderPage && $userIsSuperAdmin) {
$unpaidInvoice = Billing::checkForUnpaidInvoice(); $unpaidInvoice = Billing::checkForUnpaidInvoice();
if ($unpaidInvoice != null) { if ($unpaidInvoice != null) {
$invoiceUrl = "/billing/invoice?invoiceid=" . $unpaidInvoice['id']; $invoiceUrl = "/billing/invoice?invoiceid=" . $unpaidInvoice['id'];

View File

@ -106,11 +106,15 @@ define('UI_PLAYLISTCONTROLLER_OBJ_SESSNAME', 'PLAYLISTCONTROLLER_OBJ');
define('UI_BLOCK_SESSNAME', 'BLOCK');*/ define('UI_BLOCK_SESSNAME', 'BLOCK');*/
//WHMCS integration //WHMCS integration
define("WHMCS_API_URL", "https://account.sourcefabric.com/includes/api.php"); define("LIBRETIME_ENABLE_WHMCS", false);
define("WHMCS_API_URL", "https://account.example.org/includes/api.php");
define("SUBDOMAIN_WHMCS_CUSTOM_FIELD_NAME", "Choose your domain"); define("SUBDOMAIN_WHMCS_CUSTOM_FIELD_NAME", "Choose your domain");
//LiveChat integration
define('LIBRETIME_ENABLE_LIVECHAT', false);
//Sentry error logging //Sentry error logging
define('SENTRY_CONFIG_PATH', '/etc/airtime-saas/sentry.airtime_web.ini'); define('SENTRY_CONFIG_PATH', LIBRETIME_CONF_DIR . '/sentry.airtime_web.ini');
//Provisioning status //Provisioning status
define('PROVISIONING_STATUS_SUSPENDED' , 'Suspended'); define('PROVISIONING_STATUS_SUSPENDED' , 'Suspended');
@ -141,3 +145,6 @@ define('STATION_PODCAST_SERVICE_NAME', 'station_podcast');
//define('IMPORTED_PODCAST', 1); //define('IMPORTED_PODCAST', 1);
define('ITUNES_XML_NAMESPACE_URL', 'http://www.itunes.com/dtds/podcast-1.0.dtd'); define('ITUNES_XML_NAMESPACE_URL', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
// Billing configuration
define('LIBRETIME_ENABLE_BILLING', false);

View File

@ -7,122 +7,123 @@
* Zend_Navigation_Page::factory() when constructing * Zend_Navigation_Page::factory() when constructing
* the navigation container below. * the navigation container below.
*/ */
$pages = array( $pages = array();
array( $pages[] = array(
'label' => "<i class='icon-music icon-white'></i>"._('My Podcast'), 'label' => "<i class='icon-music icon-white'></i>"._('My Podcast'),
'module' => 'default', 'module' => 'default',
'controller' => 'podcast', 'controller' => 'podcast',
'action' => 'station', 'action' => 'station',
'resource' => 'podcast' 'resource' => 'podcast'
), );
array( $pages[] = array(
'label' => "<i class='icon-globe icon-white'></i>"._('Radio Page'), 'label' => "<i class='icon-globe icon-white'></i>"._('Radio Page'),
'uri' => '/', 'uri' => '/',
'resource' => '', 'resource' => '',
'pages' => array( 'pages' => array(
)
);
$pages[] = array(
'label' => "<i class='icon-calendar icon-white'></i>"._('Calendar'),
'module' => 'default',
'controller' => 'schedule',
'action' => 'index',
'resource' => 'schedule'
);
$pages[] = array(
'label' => "<i class='icon-wrench icon-white'></i>"._('Widgets'),
'module' => 'default',
'controller' => 'embeddablewidgets',
'action' => 'player',
'resource' => 'embeddablewidgets',
'title' => 'Widgets',
'pages' => array(
array(
'label' => _('Player'),
'module' => 'default',
'controller' => 'embeddablewidgets',
'action' => 'player',
),
array(
'label' => _('Weekly Schedule'),
'module' => 'default',
'controller' => 'embeddablewidgets',
'action' => 'schedule',
),
array(
'label' => _('Facebook'),
'module' => 'default',
'controller' => 'embeddablewidgets',
'action' => 'facebook',
) )
), )
array( );
'label' => "<i class='icon-calendar icon-white'></i>"._('Calendar'), $pages[] = array(
'module' => 'default', 'label' => "<i class='icon-cog icon-white'></i>"._("Settings"),
'controller' => 'schedule', 'resource' => 'preference',
'action' => 'index', 'action' => 'index',
'resource' => 'schedule' 'module' => 'default',
), 'controller' => 'preference',
array( 'title' => 'Settings',
'label' => "<i class='icon-wrench icon-white'></i>"._('Widgets'), 'pages' => array(
'module' => 'default', array(
'controller' => 'embeddablewidgets', 'label' => _('General'),
'action' => 'player', 'module' => 'default',
'resource' => 'embeddablewidgets', 'controller' => 'preference'
'title' => 'Widgets', ),
'pages' => array( array(
array( 'label' => _('My Profile'),
'label' => _('Player'), 'controller' => 'user',
'module' => 'default', 'action' => 'edit-user',
'controller' => 'embeddablewidgets', 'resource' => 'user'
'action' => 'player', ),
), array(
array( 'label' => _('Users'),
'label' => _('Weekly Schedule'), 'module' => 'default',
'module' => 'default', 'controller' => 'user',
'controller' => 'embeddablewidgets', 'action' => 'add-user',
'action' => 'schedule', 'resource' => 'user'
), ),
array( array(
'label' => _('Facebook'), 'label' => _('Streams'),
'module' => 'default', 'module' => 'default',
'controller' => 'embeddablewidgets', 'controller' => 'preference',
'action' => 'facebook', 'action' => 'stream-setting'
)
) )
), )
array( );
'label' => "<i class='icon-cog icon-white'></i>"._("Settings"), $pages[] = array(
'resource' => 'preference', 'label' => "<i class='icon-signal icon-white'></i>"._("Analytics"),
'action' => 'index', 'module' => 'default',
'module' => 'default', 'controller' => 'playouthistory',
'controller' => 'preference', 'action' => 'index',
'title' => 'Settings', 'resource' => 'playouthistory',
'pages' => array( 'title' => 'Analytics',
array( 'pages' => array(
'label' => _('General'), array(
'module' => 'default', 'label' => _('Playout History'),
'controller' => 'preference' 'module' => 'default',
), 'controller' => 'playouthistory',
array( 'action' => 'index',
'label' => _('My Profile'), 'resource' => 'playouthistory'
'controller' => 'user', ),
'action' => 'edit-user', array(
'resource' => 'user' 'label' => _('History Templates'),
), 'module' => 'default',
array( 'controller' => 'playouthistorytemplate',
'label' => _('Users'), 'action' => 'index',
'module' => 'default', 'resource' => 'playouthistorytemplate'
'controller' => 'user', ),
'action' => 'add-user', array(
'resource' => 'user' 'label' => _('Listener Stats'),
), 'module' => 'default',
array( 'controller' => 'listenerstat',
'label' => _('Streams'), 'action' => 'index',
'module' => 'default', 'resource' => 'listenerstat'
'controller' => 'preference', ),
'action' => 'stream-setting' )
) );
) if (LIBRETIME_ENABLE_BILLING === true) {
), $pages[] = array(
array(
'label' => "<i class='icon-signal icon-white'></i>"._("Analytics"),
'module' => 'default',
'controller' => 'playouthistory',
'action' => 'index',
'resource' => 'playouthistory',
'title' => 'Analytics',
'pages' => array(
array(
'label' => _('Playout History'),
'module' => 'default',
'controller' => 'playouthistory',
'action' => 'index',
'resource' => 'playouthistory'
),
array(
'label' => _('History Templates'),
'module' => 'default',
'controller' => 'playouthistorytemplate',
'action' => 'index',
'resource' => 'playouthistorytemplate'
),
array(
'label' => _('Listener Stats'),
'module' => 'default',
'controller' => 'listenerstat',
'action' => 'index',
'resource' => 'listenerstat'
),
)
),
array(
'label' => (Application_Model_Preference::GetPlanLevel()=="trial") ? "<i class='icon-star icon-orange'></i><span style='color: #ff5d1a'>"._('Upgrade')."</span>" : "<i class='icon-briefcase icon-white'></i>"._('Billing'), 'label' => (Application_Model_Preference::GetPlanLevel()=="trial") ? "<i class='icon-star icon-orange'></i><span style='color: #ff5d1a'>"._('Upgrade')."</span>" : "<i class='icon-briefcase icon-white'></i>"._('Billing'),
'controller' => 'billing', 'controller' => 'billing',
'action' => 'upgrade', 'action' => 'upgrade',
@ -151,48 +152,48 @@ $pages = array(
'resource' => 'billing' 'resource' => 'billing'
) )
) )
), );
array( }
'label' => "<i class='icon-question-sign icon-white'></i>"._('Help'), $pages[] = array(
'controller' => 'dashboard', 'label' => "<i class='icon-question-sign icon-white'></i>"._('Help'),
'action' => 'help', 'controller' => 'dashboard',
'resource' => 'dashboard', 'action' => 'help',
'title' => 'Help', 'resource' => 'dashboard',
'pages' => array( 'title' => 'Help',
array( 'pages' => array(
'label' => _('Getting Started'), array(
'module' => 'default', 'label' => _('Getting Started'),
'controller' => 'dashboard', 'module' => 'default',
'action' => 'help', 'controller' => 'dashboard',
'resource' => 'dashboard' 'action' => 'help',
), 'resource' => 'dashboard'
array( ),
'label' => _('FAQ'), array(
'uri' => FAQ_URL, 'label' => _('FAQ'),
'target' => "_blank" 'uri' => FAQ_URL,
), 'target' => "_blank"
array( ),
'label' => _('User Manual'), array(
'uri' => USER_MANUAL_URL, 'label' => _('User Manual'),
'target' => "_blank" 'uri' => USER_MANUAL_URL,
), 'target' => "_blank"
array( ),
'label' => _('File a Support Ticket'), array(
'uri' => SUPPORT_TICKET_URL, 'label' => _('File a Support Ticket'),
'target' => "_blank" 'uri' => SUPPORT_TICKET_URL,
), 'target' => "_blank"
array( ),
'label' => _(sprintf("Help Translate %s", PRODUCT_NAME)), array(
'uri' => AIRTIME_TRANSIFEX_URL, 'label' => _(sprintf("Help Translate %s", PRODUCT_NAME)),
'target' => "_blank" 'uri' => AIRTIME_TRANSIFEX_URL,
), 'target' => "_blank"
array( ),
'label' => _('What\'s New?'), array(
'uri' => UI_REVAMP_YOUTUBE_URL, 'label' => _('What\'s New?'),
'target' => "_blank" 'uri' => UI_REVAMP_YOUTUBE_URL,
) 'target' => "_blank"
) )
), )
); );

View File

@ -443,7 +443,7 @@ class LibraryController extends Zend_Controller_Action
$this->_helper->layout->disableLayout(); $this->_helper->layout->disableLayout();
if (!Billing::isStationPodcastAllowed()) { if (LIBRETIME_ENABLE_BILLING === true && !Billing::isStationPodcastAllowed()) {
$this->renderScript("podcast/featureupgrade-pane.phtml"); $this->renderScript("podcast/featureupgrade-pane.phtml");
} }

View File

@ -45,7 +45,7 @@ class LoginController extends Zend_Controller_Action
//uses separate layout without a navigation. //uses separate layout without a navigation.
$this->_helper->layout->setLayout('login'); $this->_helper->layout->setLayout('login');
$error = false; $this->view->error = false;
$baseUrl = Application_Common_OsPath::getBaseDir(); $baseUrl = Application_Common_OsPath::getBaseDir();
@ -92,7 +92,7 @@ class LoginController extends Zend_Controller_Action
Application_Model_Preference::SetUserLocale($locale); Application_Model_Preference::SetUserLocale($locale);
$this->_redirect('showbuilder'); $this->_redirect('showbuilder');
} else { } elseif (LIBRETIME_ENABLE_WHMCS) {
$email = $form->getValue('username'); $email = $form->getValue('username');
$authAdapter = new WHMCS_Auth_Adapter("admin", $email, $password); $authAdapter = new WHMCS_Auth_Adapter("admin", $email, $password);
$auth = Zend_Auth::getInstance(); $auth = Zend_Auth::getInstance();
@ -105,23 +105,14 @@ class LoginController extends Zend_Controller_Action
$this->_redirect('showbuilder'); $this->_redirect('showbuilder');
} }
else { else {
$message = _("Wrong username or password provided. Please try again."); $form = $this->loginError($username);
Application_Model_Subjects::increaseLoginAttempts($username);
Application_Model_LoginAttempts::increaseAttempts($_SERVER['REMOTE_ADDR']);
$form = new Application_Form_Login();
$error = true;
//Only show the captcha if you get your login wrong 4 times in a row.
if (Application_Model_Subjects::getLoginAttempts($username) > 3)
{
$form->addRecaptcha();
}
} }
} else {
$form = $this->loginError($username);
} }
} }
} }
$this->view->message = $message;
$this->view->error = $error;
$this->view->form = $form; $this->view->form = $form;
$this->view->airtimeVersion = Application_Model_Preference::GetAirtimeVersion(); $this->view->airtimeVersion = Application_Model_Preference::GetAirtimeVersion();
$this->view->airtimeCopyright = AIRTIME_COPYRIGHT_DATE; $this->view->airtimeCopyright = AIRTIME_COPYRIGHT_DATE;
@ -260,4 +251,24 @@ class LoginController extends Zend_Controller_Action
$this->view->form = $form; $this->view->form = $form;
} }
/**
* populates view with results from a login error and adds a new form
*
* @param String $username user that failed to login
* @return new form
*/
private function loginError($username)
{
$this->view->message = _("Wrong username or password provided. Please try again.");
Application_Model_Subjects::increaseLoginAttempts($username);
Application_Model_LoginAttempts::increaseAttempts($_SERVER['REMOTE_ADDR']);
$form = new Application_Form_Login();
$this->view->error = true;
//Only show the captcha if you get your login wrong 4 times in a row.
if (Application_Model_Subjects::getLoginAttempts($username) > 3) {
$form->addRecaptcha();
}
return $form;
}
} }

View File

@ -226,7 +226,7 @@ class PlaylistController extends Zend_Controller_Action
$obj = new $objInfo['className']($id); $obj = new $objInfo['className']($id);
$this->createFullResponse($obj); $this->createFullResponse($obj);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound($type);
} catch (Exception $e) { } catch (Exception $e) {
$this->playlistUnknownError($e); $this->playlistUnknownError($e);
} }

View File

@ -27,7 +27,7 @@ class PodcastController extends Zend_Controller_Action {
*/ */
public function stationAction() { public function stationAction() {
if (!Billing::isStationPodcastAllowed()) { if (LIBRETIME_ENABLE_BILLING === true && !Billing::isStationPodcastAllowed()) {
$this->render("featureupgrade-page"); $this->render("featureupgrade-page");
return; return;
} }

View File

@ -224,7 +224,8 @@ class PageLayoutInitPlugin extends Zend_Controller_Plugin_Abstract
} }
$view->headScript()->appendScript("var userType = '$userType';"); $view->headScript()->appendScript("var userType = '$userType';");
if (array_key_exists('REQUEST_URI', $_SERVER) //Doesn't exist for unit tests if (LIBRETIME_ENABLE_LIVECHAT === true
&& array_key_exists('REQUEST_URI', $_SERVER) //Doesn't exist for unit tests
&& strpos($_SERVER['REQUEST_URI'], 'Dashboard/stream-player') === false && strpos($_SERVER['REQUEST_URI'], 'Dashboard/stream-player') === false
&& strpos($_SERVER['REQUEST_URI'], 'audiopreview') === false && strpos($_SERVER['REQUEST_URI'], 'audiopreview') === false
&& $_SERVER['REQUEST_URI'] != "/") { && $_SERVER['REQUEST_URI'] != "/") {

View File

@ -131,7 +131,7 @@ class Application_Form_EditUser extends Zend_Form
$timezone->setDecorators(array('ViewHelper')); $timezone->setDecorators(array('ViewHelper'));
$this->addElement($timezone); $this->addElement($timezone);
if (Application_Model_User::getCurrentUser()->isSuperAdmin()) { if (LIBRETIME_ENABLE_BILLING === true && Application_Model_User::getCurrentUser()->isSuperAdmin()) {
$elemsToDisable = array($password, $passwordVerify, $email, $firstName, $lastName, $elemsToDisable = array($password, $passwordVerify, $email, $firstName, $lastName,
$cellPhone, $skype, $jabber); $cellPhone, $skype, $jabber);
foreach ($elemsToDisable as $element) { foreach ($elemsToDisable as $element) {

View File

@ -1573,7 +1573,7 @@ class Application_Model_Preference
* @return int either 0 (public) or 1 (private) * @return int either 0 (public) or 1 (private)
*/ */
public static function getStationPodcastPrivacy() { public static function getStationPodcastPrivacy() {
if (!Billing::isStationPodcastAllowed()) { if (LIBRETIME_ENABLE_BILLING === true && !Billing::isStationPodcastAllowed()) {
// return private setting // return private setting
return 1; return 1;
} }

View File

@ -81,16 +81,18 @@ class Application_Model_RabbitMq
public static function getRmqConfigPath() { public static function getRmqConfigPath() {
//Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global //Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global
//and shared between all instances on Airtime Pro. //and shared between all instances on Airtime Pro.
//
// todo: rewrite me to only use the config class and not access /etc/airtime directly
$CC_CONFIG = Config::getConfig(); $CC_CONFIG = Config::getConfig();
$devEnv = "production"; //Default $devEnv = "production"; //Default
if (array_key_exists("dev_env", $CC_CONFIG)) { if (array_key_exists("dev_env", $CC_CONFIG)) {
$devEnv = $CC_CONFIG["dev_env"]; $devEnv = $CC_CONFIG["dev_env"];
} }
$rmq_config_path = "/etc/airtime-saas/".$devEnv."/rabbitmq-analyzer.ini"; $rmq_config_path = LIBRETIME_CONF_DIR . '/' . $devEnv."/rabbitmq-analyzer.ini";
if (!file_exists($rmq_config_path)) { if (!file_exists($rmq_config_path)) {
// If the dev env specific rabbitmq-analyzer.ini doesn't exist default // If the dev env specific rabbitmq-analyzer.ini doesn't exist default
// to the production rabbitmq-analyzer.ini // to the production rabbitmq-analyzer.ini
$rmq_config_path = "/etc/airtime-saas/production/rabbitmq-analyzer.ini"; $rmq_config_path = LIBRETIME_CONF_PATH . "/production/rabbitmq-analyzer.ini";
} }
return $rmq_config_path; return $rmq_config_path;
} }

View File

@ -1,7 +1,7 @@
<h2><?php echo _("My Profile") ?></h2> <h2><?php echo _("My Profile") ?></h2>
<div id="current-user-container"> <div id="current-user-container">
<?php if(Application_Model_User::getCurrentUser()->isSuperAdmin()) : ?> <?php if(LIBRETIME_ENABLE_BILLING === true && Application_Model_User::getCurrentUser()->isSuperAdmin()) : ?>
<div id="user_details_superadmin_message"> <div id="user_details_superadmin_message">
<p class="alert alert-error"> <p class="alert alert-error">
<?=sprintf(_("<b>Note:</b> Since you're the station owner, your account information can be edited in <a href=\"%s\">Billing Settings</a> instead."), "/billing/client");?> <?=sprintf(_("<b>Note:</b> Since you're the station owner, your account information can be edited in <a href=\"%s\">Billing Settings</a> instead."), "/billing/client");?>

View File

@ -9,7 +9,7 @@
</div> </div>
<?php <?php
if (Billing::isStationPodcastAllowed()) { ?> if (LIBRETIME_ENABLE_BILLING === true && Billing::isStationPodcastAllowed()) { ?>
<h3 class="collapsible-header" id="soundcloud-heading"><span class="arrow-icon"></span><?php echo _("SoundCloud Settings") ?></h3> <h3 class="collapsible-header" id="soundcloud-heading"><span class="arrow-icon"></span><?php echo _("SoundCloud Settings") ?></h3>
<div class="collapsible-content" id="soundcloud-settings"> <div class="collapsible-content" id="soundcloud-settings">
<?php echo $this->element->getSubform('preferences_soundcloud') ?> <?php echo $this->element->getSubform('preferences_soundcloud') ?>

View File

@ -26,9 +26,11 @@
</table> </table>
</div> </div>
</div> </div>
<?php if (LIBRETIME_ENABLE_BILLING === true) { ?>
<div class="user-data" id="user_details_superadmin_message" style="display: none; margin-top: 105px; text-align: center;"> <div class="user-data" id="user_details_superadmin_message" style="display: none; margin-top: 105px; text-align: center;">
<?=sprintf(_("Super Admin details can be changed in your <a href=\"%s\">Billing Settings</a>."), "/billing/client");?> <?=sprintf(_("Super Admin details can be changed in your <a href=\"%s\">Billing Settings</a>."), "/billing/client");?>
</div> </div>
<?php } ?>
<div class="user-data simple-formblock" id="user_details"> <div class="user-data simple-formblock" id="user_details">
<?php echo $this->successMessage ?> <?php echo $this->successMessage ?>
<fieldset class="padded"> <fieldset class="padded">

View File

@ -25,8 +25,7 @@ require_once(dirname(dirname( __DIR__)) . "/application/models/airtime/CcMusicDi
class MediaSetup extends Setup { class MediaSetup extends Setup {
const MEDIA_FOLDER = "mediaFolder"; const MEDIA_FOLDER = "mediaFolder";
const AIRTIME_CONF_PATH = "/etc/airtime/airtime.conf"; const LIBRETIME_CONF_FILE_NAME = "airtime.conf";
const RMQ_INI_BASE_PATH = "/etc/airtime-saas/";
const RMQ_INI_FILE_NAME = "rabbitmq-analyzer.ini"; const RMQ_INI_FILE_NAME = "rabbitmq-analyzer.ini";
static $path; static $path;
@ -77,8 +76,11 @@ class MediaSetup extends Setup {
* airtime.conf to airtime.conf.tmp during the setup process. Now that we're done, * airtime.conf to airtime.conf.tmp during the setup process. Now that we're done,
* we can rename it to airtime.conf.bak to avoid confusion. * we can rename it to airtime.conf.bak to avoid confusion.
*/ */
if (file_exists(self::AIRTIME_CONF_PATH . ".tmp")) { $fileName = LIBRETIME_CONF_DIR . '/' . self::LIBRETIME_CONF_FILE_NAME;
rename(self::AIRTIME_CONF_PATH . ".tmp", self::AIRTIME_CONF_PATH . ".bak"); $tmpFile = $fileName . '.tmp';
$bakFile = $fileName . '.bak';
if (file_exists($tmpFile)) {
rename($tmpFile, $bakFile);
} }
} else { } else {
self::$message = "Failed to move airtime.conf; /etc/airtime doesn't exist!"; self::$message = "Failed to move airtime.conf; /etc/airtime doesn't exist!";
@ -96,7 +98,7 @@ class MediaSetup extends Setup {
* @return boolean false if either of the copy or removal operations fail * @return boolean false if either of the copy or removal operations fail
*/ */
function moveAirtimeConfig() { function moveAirtimeConfig() {
return copy(AIRTIME_CONF_TEMP_PATH, self::AIRTIME_CONF_PATH) return copy(AIRTIME_CONF_TEMP_PATH, LIBRETIME_CONF_DIR . '/' . self::LIBRETIME_CONF_FILE_NAME)
&& unlink(AIRTIME_CONF_TEMP_PATH); && unlink(AIRTIME_CONF_TEMP_PATH);
} }
@ -105,8 +107,8 @@ class MediaSetup extends Setup {
* @return boolean false if either of the copy or removal operations fail * @return boolean false if either of the copy or removal operations fail
*/ */
function moveRmqConfig() { function moveRmqConfig() {
return copy(RMQ_INI_TEMP_PATH, self::RMQ_INI_BASE_PATH . self::RMQ_INI_FILE_NAME) return copy(RMQ_INI_TEMP_PATH, LIBRETIME_CONF_DIR . '/' . self::RMQ_INI_FILE_NAME)
&& copy(RMQ_INI_TEMP_PATH, self::RMQ_INI_BASE_PATH . "production/" . self::RMQ_INI_FILE_NAME) && copy(RMQ_INI_TEMP_PATH, LIBRETIME_CONF_DIR . '/production/' . self::RMQ_INI_FILE_NAME)
&& unlink(RMQ_INI_TEMP_PATH); && unlink(RMQ_INI_TEMP_PATH);
} }

14
docs/_css/term.css Normal file
View File

@ -0,0 +1,14 @@
pre.codehilite > code,
div.codehilite > pre {
color: #808080;
padding: 1em;
border-radius: 3px;
font-size: 110%;
font-weight: bold;
overflow: auto;
}
pre.codehilite > code.language-console > span,
div.codehilite > pre > span[style*="color: #AA22FF"] {
color: #808080 !important;
}

28
docs/documentation.md Normal file
View File

@ -0,0 +1,28 @@
Documentation
=============
The LibreTime documentation site is generated with [mkdocs](http://www.mkdocs.org/). To get started contributing to this project, fork it on Github. Then install mkdocs and clone this repo locally:
:::bash
sudo brew install python # For OSX users
sudo aptitude install python-pip # For Debian/Ubuntu users
sudo pip install mkdocs
git clone https://github.com/libretime/libretime
cd libretime
git remote add sandbox https://github.com/<username>/libretime # URL for your fork
mkdocs build --clean
mkdocs serve
Your local LibreTime docs site should now be available for browsing: [http://localhost:8888/](http://localhost:8888/).
When you find a typo, an error, unclear or missing explanations or instructions, open a new terminal and start editing. Your changes should be reflected automatically on the local server. Find the page youd like to edit; everything is in the docs/ directory. Make your changes, commit and push them, and start a pull request:
:::bash
git checkout -b fix_typo
vi docs/index.md # Add/edit/remove whatever you see fit. Be bold!
mkdocs build --clean; mkdocs serve # Go check your changes. Well wait...
git diff # Make sure there arent any unintended changes.
git commit -am”Fixed typo.” # Useful commit message are a good habit.
git push sandbox fix_typo
Visit your fork on Github and start a PR.

9
docs/features.md Normal file
View File

@ -0,0 +1,9 @@
Features
========
TBD
Screenshots
-----------
TBD

25
docs/index.md Normal file
View File

@ -0,0 +1,25 @@
Welcome to LibreTime
====================
LibreTime makes it easy to run your own online radio station. Check out some [features](features.md) and [screenshots](features.md#screenshots), then [install it](install.md) and start broadcasting!
LibreTime is Free/Libre and Open Source Software (FLOSS). Among other things, this means that you have the freedom to:
* Run it royalty-free for as long as you like.
* Read and alter the code that makes it work (or hire someone to do this for you!)
* Contribute documentation, bug-fixes, etc. so that everyone in the community benefits.
LibreTime is a fork of AirTime due to stalled development of the FLOSS version. For background on this, see this [open letter to the Airtime community](https://gist.github.com/hairmare/8c03b69c9accc90cfe31fd7e77c3b07d).
Getting Started
---------------
The easiest way to check out LibreTime for yourself is to run a local instance in a virtual machine. Assuming you already have Git, Vagrant and Virtualbox installed, just run:
:::bash
git clone https://github.com/libretime/libretime.git
cd libretime
vagrant up
Of course, this setup isn't appropriate for production use. For that, check out our [installation instructions](install.md).

9
docs/install.md Normal file
View File

@ -0,0 +1,9 @@
Installing LibreTime
====================
LibreTime should generally be installed on a dedicated host. By default, its installer will install and configure all its dependencies. At the moment, the installer works best on Ubuntu Trusty.
:::bash
./install
Plans are in the works for ```.deb``` and ```.rpm``` packages, as well as Docker and AWS images.

10
docs/scripts/install.sh Executable file
View File

@ -0,0 +1,10 @@
#! /bin/sh
echo "Updating Apt."
apt-get update > /dev/null
echo "Ensuring Pip is installed."
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python-pip > /dev/null
echo "Updating Pip."
pip install pip -q -q --upgrade > /dev/null
echo "Ensuring Mkdocs is installed."
pip install -q mkdocs > /dev/null

10
docs/scripts/serve.sh Executable file
View File

@ -0,0 +1,10 @@
#! /bin/sh
cd /vagrant
echo "Stopping any running Mkdocs servers."
pkill mkdocs
echo "Building Mkdocs documentation."
mkdocs build --clean -q > /dev/null
echo "Launching Mkdocs server."
mkdocs serve > /dev/null 2>&1 &
echo "Visit http://localhost:8888 to see the LibreTime documentation."

20
mkdocs.yml Normal file
View File

@ -0,0 +1,20 @@
site_name: LibreTime
theme: readthedocs
dev_addr: '0.0.0.0:8888'
site_dir: 'build/docs'
markdown_extensions:
- codehilite:
noclasses: True
pygments_style: emacs
extra_css:
- '_css/term.css'
pages:
- 'Home': index.md
- 'Features': features.md
- 'Install': install.md
- 'Development':
- 'Testing': testing.md
- 'Documentation': documentation.md

View File

@ -28,7 +28,7 @@ Developers
To debug, you can run celery directly from the command line: To debug, you can run celery directly from the command line:
$ cd /my/airtime/root/python_apps/airtime-celery $ cd /my/airtime/root/python_apps/airtime-celery
$ RMQ_CONFIG_FILE=/etc/airtime/airtime.conf celery -A airtime-celery.tasks worker --loglevel=info $ RMQ_CONFIG_FILE=${LIBRETIME_CONF_DIR}/airtime.conf celery -A airtime-celery.tasks worker --loglevel=info
This worker can be run alongside the service without issue. This worker can be run alongside the service without issue.
@ -57,8 +57,8 @@ If you run into issues getting Celery to accept tasks from Airtime:
2) Check the log file (/var/log/airtime/airtime-celery[-DEV_ENV].log) to make sure Celery started correctly. 2) Check the log file (/var/log/airtime/airtime-celery[-DEV_ENV].log) to make sure Celery started correctly.
3) Check your /etc/airtime/airtime.conf rabbitmq settings. Make sure the settings here align with 3) Check your $LIBRETIME_CONF_DIR/airtime.conf rabbitmq settings. Make sure the settings here align with
/etc/airtime-saas/production/rabbitmq.ini. $LIBRETIME_CONF_DIR/$ENVIRONMENT/rabbitmq.ini.
4) Check RabbitMQ to make sure the celeryresults and task queues were created in the correct vhost. 4) Check RabbitMQ to make sure the celeryresults and task queues were created in the correct vhost.

View File

@ -10,7 +10,7 @@ from boto.s3.key import Key
# https://github.com/docker/docker-registry/issues/400 # https://github.com/docker/docker-registry/issues/400
u'fix getaddrinfo deadlock'.encode('idna') u'fix getaddrinfo deadlock'.encode('idna')
CLOUD_CONFIG_PATH = '/etc/airtime-saas/cloud_storage.conf' CLOUD_CONFIG_PATH = os.path.join(os.getenv('LIBRETIME_CONF_DIR', '/etc/airtime'), 'cloud_storage.conf')
STORAGE_BACKEND_FILE = "file" STORAGE_BACKEND_FILE = "file"
SOCKET_TIMEOUT = 240 SOCKET_TIMEOUT = 240

View File

@ -6,7 +6,7 @@ from libcloud.storage.providers import get_driver
from libcloud.storage.types import Provider, ContainerDoesNotExistError, ObjectDoesNotExistError from libcloud.storage.types import Provider, ContainerDoesNotExistError, ObjectDoesNotExistError
CLOUD_CONFIG_PATH = '/etc/airtime-saas/cloud_storage.conf' CLOUD_CONFIG_PATH = os.path.join(os.getenv('LIBRETIME_CONF_DIR', '/etc/airtime'), 'cloud_storage.conf')
STORAGE_BACKEND_FILE = "file" STORAGE_BACKEND_FILE = "file"
class CloudStorageUploader: class CloudStorageUploader:

View File

@ -8,8 +8,9 @@ import os
import airtime_analyzer.airtime_analyzer as aa import airtime_analyzer.airtime_analyzer as aa
VERSION = "1.0" VERSION = "1.0"
DEFAULT_RMQ_CONFIG_PATH = '/etc/airtime/airtime.conf' LIBRETIME_CONF_DIR = os.getenv('LIBRETIME_CONF_DIR', '/etc/airtime')
DEFAULT_CLOUD_STORAGE_CONFIG_PATH = '/etc/airtime-saas/production/cloud_storage.conf' DEFAULT_RMQ_CONFIG_PATH = os.path.join(LIBRETIME_CONF_DIR, 'airtime.conf')
DEFAULT_CLOUD_STORAGE_CONFIG_PATH = os.path.join(LIBRETIME_CONF_DIR, os.getenv('ENVIRONMENT', 'production'), 'airtime.conf')
DEFAULT_HTTP_RETRY_PATH = '/tmp/airtime_analyzer_http_retries' DEFAULT_HTTP_RETRY_PATH = '/tmp/airtime_analyzer_http_retries'
def run(): def run():

View File

@ -22,7 +22,7 @@ def teardown():
def test_basic(): def test_basic():
filename = os.path.basename(DEFAULT_AUDIO_FILE) filename = os.path.basename(DEFAULT_AUDIO_FILE)
q = Queue.Queue() q = Queue.Queue()
#cloud_storage_config_path = '/etc/airtime-saas/production/cloud_storage.conf' #cloud_storage_config_path = os.path.join(os.getenv('LIBRETIME_CONF_DIR', '/etc/airtime'), '/production/cloud_storage.conf')
#cloud_storage_config = config_file.read_config_file(cloud_storage_config_path) #cloud_storage_config = config_file.read_config_file(cloud_storage_config_path)
cloud_storage_config = SafeConfigParser() cloud_storage_config = SafeConfigParser()
cloud_storage_config.add_section("current_backend") cloud_storage_config.add_section("current_backend")