Merge branch 'devel' into mediamonitor2

Conflicts:
	python_apps/api_clients/api_client.py
This commit is contained in:
Rudi Grinberg 2012-07-16 17:41:36 -04:00
commit 20e32b98ba
31 changed files with 253 additions and 143 deletions

View file

@ -90,12 +90,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$userType = ""; $userType = "";
} }
$view->headScript()->appendScript("var userType = '$userType';"); $view->headScript()->appendScript("var userType = '$userType';");
if (Application_Model_Preference::GetPlanLevel() != "disabled"
&& !($_SERVER['REQUEST_URI'] == '/Dashboard/stream-player' || $_SERVER['REQUEST_URI'] == '/audiopreview/audio-preview-player')) {
$client_id = Application_Model_Preference::GetClientId();
$view->headScript()->appendScript("var livechat_client_id = '$client_id';");
$view->headScript()->appendFile($baseUrl . '/js/airtime/common/livechat.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
}
if(isset($CC_CONFIG['demo']) && $CC_CONFIG['demo'] == 1){ if(isset($CC_CONFIG['demo']) && $CC_CONFIG['demo'] == 1){
$view->headScript()->appendFile($baseUrl.'/js/libs/google-analytics.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $view->headScript()->appendFile($baseUrl.'/js/libs/google-analytics.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
} }

View file

@ -2,7 +2,7 @@
define('AIRTIME_COPYRIGHT_DATE', '2010-2012'); define('AIRTIME_COPYRIGHT_DATE', '2010-2012');
define('AIRTIME_REST_VERSION', '1.1'); define('AIRTIME_REST_VERSION', '1.1');
define('AIRTIME_API_VERSION', '1.0'); define('AIRTIME_API_VERSION', '1.1');
// Metadata Keys for files // Metadata Keys for files
define('MDATA_KEY_FILEPATH', 'filepath'); define('MDATA_KEY_FILEPATH', 'filepath');

View file

@ -262,30 +262,28 @@ class ApiController extends Zend_Controller_Action
$request = $this->getRequest(); $request = $this->getRequest();
$type = $request->getParam('type'); $type = $request->getParam('type');
if ($type == "endofday") { if ($type == "endofday") {
// make getNextShows use end of day
$utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc();
$result = array("env"=>APPLICATION_ENV,
"schedulerTime"=>gmdate("Y-m-d H:i:s"),
"nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, 5, $utcTimeEnd));
Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp"));
} else {
$limit = $request->getParam('limit'); $limit = $request->getParam('limit');
if ($limit == "" || !is_numeric($limit)) { if($limit == "" || !is_numeric($limit)) {
$limit = "5"; $limit = "5";
} }
// make GetNextShows use end of day
$utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc();
$result = array("env"=>APPLICATION_ENV,
"schedulerTime"=>gmdate("Y-m-d H:i:s"),
"nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd));
Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp"));
} else {
$result = Application_Model_Schedule::GetPlayOrderRange(); $result = Application_Model_Schedule::GetPlayOrderRange();
//Convert from UTC to localtime for user. //Convert from UTC to localtime for Web Browser.
Application_Model_Show::convertToLocalTimeZone($result["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); Application_Model_Show::convertToLocalTimeZone($result["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp"));
Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); Application_Model_Show::convertToLocalTimeZone($result["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp"));
} }
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; //used by caller to determine if the airtime they are running or widgets in use is out of date. $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; //used by caller to determine if the airtime they are running or widgets in use is out of date.
//echo json_encode($result);
header("Content-type: text/javascript"); header("Content-type: text/javascript");
echo $_GET['callback'].'('.json_encode($result).')'; echo $_GET['callback'].'('.json_encode($result).')';
} else { } else {

View file

@ -125,28 +125,11 @@ class LibraryController extends Zend_Controller_Action
} }
} }
$hasPermission = true; try {
if (count($playlists)) { Application_Model_Playlist::deletePlaylists($playlists, $user->getId());
// make sure use has permission to delete all playslists in the list } catch (PlaylistNoPermissionException $e) {
if (!$isAdminOrPM) { $this->view->message = "You don't have permission to delete selected playlists/files.";
foreach ($playlists as $pid) {
$pl = new Application_Model_Playlist($pid);
if ($pl->getCreatorId() != $user->getId()) {
$hasPermission = false;
}
}
}
}
if (!$isAdminOrPM && count($files)) {
$hasPermission = false;
}
if (!$hasPermission) {
$this->view->message = "You don't have a permission to delete all playlists/files that are selected.";
return; return;
} else {
Application_Model_Playlist::DeletePlaylists($playlists);
} }
foreach ($files as $id) { foreach ($files as $id) {

View file

@ -82,7 +82,7 @@ class PlaylistController extends Zend_Controller_Action
} }
} }
private function playlistOutdated($pl, $e) private function playlistOutdated($e)
{ {
$this->view->error = $e->getMessage(); $this->view->error = $e->getMessage();
} }
@ -96,6 +96,10 @@ class PlaylistController extends Zend_Controller_Action
$this->createFullResponse(null); $this->createFullResponse(null);
} }
private function playlistNoPermission(){
$this->view->error = "You don't have permission to delete selected playlist(s).";
}
private function playlistUnknownError($e) private function playlistUnknownError($e)
{ {
$this->view->error = "Something went wrong."; $this->view->error = "Something went wrong.";
@ -137,7 +141,13 @@ class PlaylistController extends Zend_Controller_Action
try { try {
if (isset($this->pl_sess->id)) { if (isset($this->pl_sess->id)) {
$pl = new Application_Model_Playlist($this->pl_sess->id); $pl = new Application_Model_Playlist($this->pl_sess->id);
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if($isAdminOrPM || $pl->getCreatorId() == $userInfo->id){
$this->view->pl = $pl; $this->view->pl = $pl;
}
$formatter = new LengthFormatter($pl->getLength()); $formatter = new LengthFormatter($pl->getLength());
$this->view->length = $formatter->format(); $this->view->length = $formatter->format();
@ -187,6 +197,9 @@ class PlaylistController extends Zend_Controller_Action
$ids = (!is_array($ids)) ? array($ids) : $ids; $ids = (!is_array($ids)) ? array($ids) : $ids;
$pl = null; $pl = null;
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
try { try {
Logging::log("Currently active playlist {$this->pl_sess->id}"); Logging::log("Currently active playlist {$this->pl_sess->id}");
@ -198,9 +211,13 @@ class PlaylistController extends Zend_Controller_Action
$pl = new Application_Model_Playlist($this->pl_sess->id); $pl = new Application_Model_Playlist($this->pl_sess->id);
} }
Application_Model_Playlist::DeletePlaylists($ids); Application_Model_Playlist::deletePlaylists($ids, $userInfo->id);
$this->createFullResponse($pl); $this->createFullResponse($pl);
} catch (PlaylistNotFoundException $e) { }
catch (PlaylistNoPermissionException $e) {
$this->playlistNoPermission();
}
catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
$this->playlistUnknownError($e); $this->playlistUnknownError($e);
@ -219,7 +236,7 @@ class PlaylistController extends Zend_Controller_Action
$pl->addAudioClips($ids, $afterItem, $addType); $pl->addAudioClips($ids, $afterItem, $addType);
$this->createUpdateResponse($pl); $this->createUpdateResponse($pl);
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -239,7 +256,7 @@ class PlaylistController extends Zend_Controller_Action
$pl->moveAudioClips($ids, $afterItem); $pl->moveAudioClips($ids, $afterItem);
$this->createUpdateResponse($pl); $this->createUpdateResponse($pl);
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -258,7 +275,7 @@ class PlaylistController extends Zend_Controller_Action
$pl->delAudioClips($ids); $pl->delAudioClips($ids);
$this->createUpdateResponse($pl); $this->createUpdateResponse($pl);
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -283,7 +300,7 @@ class PlaylistController extends Zend_Controller_Action
$this->view->cue_error = $response["error"]; $this->view->cue_error = $response["error"];
} }
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -308,7 +325,7 @@ class PlaylistController extends Zend_Controller_Action
$this->view->fade_error = $response["error"]; $this->view->fade_error = $response["error"];
} }
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -326,7 +343,7 @@ class PlaylistController extends Zend_Controller_Action
$fades = $pl->getFadeInfo($pl->getSize()-1); $fades = $pl->getFadeInfo($pl->getSize()-1);
$this->view->fadeOut = $fades[1]; $this->view->fadeOut = $fades[1];
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -349,7 +366,7 @@ class PlaylistController extends Zend_Controller_Action
$pl->setPlaylistfades($fadeIn, $fadeOut); $pl->setPlaylistfades($fadeIn, $fadeOut);
$this->view->modified = $pl->getLastModified("U"); $this->view->modified = $pl->getLastModified("U");
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -367,7 +384,7 @@ class PlaylistController extends Zend_Controller_Action
$this->view->playlistName = $name; $this->view->playlistName = $name;
$this->view->modified = $pl->getLastModified("U"); $this->view->modified = $pl->getLastModified("U");
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {
@ -385,7 +402,7 @@ class PlaylistController extends Zend_Controller_Action
$this->view->description = $pl->getDescription(); $this->view->description = $pl->getDescription();
$this->view->modified = $pl->getLastModified("U"); $this->view->modified = $pl->getLastModified("U");
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($pl, $e); $this->playlistOutdated($e);
} catch (PlaylistNotFoundException $e) { } catch (PlaylistNotFoundException $e) {
$this->playlistNotFound(); $this->playlistNotFound();
} catch (Exception $e) { } catch (Exception $e) {

View file

@ -454,10 +454,11 @@ class Application_Model_Playlist
->filterByDbPosition($pos) ->filterByDbPosition($pos)
->findOne(); ->findOne();
#Propel returns values in form 00.000000 format which is for only seconds. #Propel returns values in form 00.000000 format which is for only seconds.
$fadeIn = $row->getDbFadein(); $fadeIn = $row->getDbFadein();
$fadeOut = $row->getDbFadeout(); $fadeOut = $row->getDbFadeout();
return array($fadeIn, $fadeOut); return array($fadeIn, $fadeOut);
} }
@ -800,12 +801,33 @@ class Application_Model_Playlist
* Delete playlists that match the ids.. * Delete playlists that match the ids..
* @param array $p_ids * @param array $p_ids
*/ */
public static function DeletePlaylists($p_ids) public static function deletePlaylists($p_ids, $p_userId)
{ {
$leftOver = self::playlistsNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcPlaylistQuery::create()->findPKs($p_ids)->delete(); CcPlaylistQuery::create()->findPKs($p_ids)->delete();
} else {
throw new PlaylistNoPermissionException;
}
}
// This function returns that are not owen by $p_user_id among $p_ids
private static function playlistsNotOwnedByUser($p_ids, $p_userId){
$ownedByUser = CcPlaylistQuery::create()->filterByDbCreatorId($p_userId)->find()->getData();
$selectedPls = $p_ids;
$ownedPls = array();
foreach ($ownedByUser as $pl) {
if (in_array($pl->getDbId(), $selectedPls)) {
$ownedPls[] = $pl->getDbId();
}
}
$leftOvers = array_diff($selectedPls, $ownedPls);
return $leftOvers;
} }
} // class Playlist } // class Playlist
class PlaylistNotFoundException extends Exception {} class PlaylistNotFoundException extends Exception {}
class PlaylistNoPermissionException extends Exception {}
class PlaylistOutDatedException extends Exception {} class PlaylistOutDatedException extends Exception {}

View file

@ -32,6 +32,7 @@ class Application_Model_Schedule
{ {
if (!is_int($p_prev) || !is_int($p_next)) { if (!is_int($p_prev) || !is_int($p_next)) {
//must enter integers to specify ranges //must enter integers to specify ranges
Logging::log("Invalid range parameters: $p_prev or $p_next");
return array(); return array();
} }
@ -49,7 +50,6 @@ class Application_Model_Schedule
"schedulerTime"=>$timeNow, "schedulerTime"=>$timeNow,
"previous"=>$results['previous'] !=null?$results['previous']:(count($shows['previousShow'])>0?$shows['previousShow'][0]:null), "previous"=>$results['previous'] !=null?$results['previous']:(count($shows['previousShow'])>0?$shows['previousShow'][0]:null),
"current"=>$results['current'] !=null?$results['current']:((count($shows['currentShow'])>0 && $shows['currentShow'][0]['record'] == 1)?$shows['currentShow'][0]:null), "current"=>$results['current'] !=null?$results['current']:((count($shows['currentShow'])>0 && $shows['currentShow'][0]['record'] == 1)?$shows['currentShow'][0]:null),
//"current"=>$results['current'] !=null?$results['current']:(count($shows['currentShow'])>0?$shows['currentShow'][0]:null),
"next"=> $results['next'] !=null?$results['next']:(count($shows['nextShow'])>0?$shows['nextShow'][0]:null), "next"=> $results['next'] !=null?$results['next']:(count($shows['nextShow'])>0?$shows['nextShow'][0]:null),
"currentShow"=>$shows['currentShow'], "currentShow"=>$shows['currentShow'],
"nextShow"=>$shows['nextShow'], "nextShow"=>$shows['nextShow'],

View file

@ -1876,9 +1876,9 @@ class Application_Model_Show
/** /**
* Given a start time $timeStart and end time $timeEnd, returns the next $limit * Given a start time $timeStart and end time $timeEnd, returns the next $limit
* number of shows within the time interval; * number of shows within the time interval
* If $timeEnd not given, shows within next 48 hours from $timeStart are returned; * If $timeEnd not given, shows within next 48 hours from $timeStart are returned
* If $limit not given, all shows within the intervals are returns; * If $limit not given, all shows within the intervals are returned
* Times are all in UTC time. * Times are all in UTC time.
* *
* @param String $timeStart - interval start time (in UTC) * @param String $timeStart - interval start time (in UTC)

View file

@ -118,6 +118,14 @@ function stringToColor(s)
return intToRGB(hashCode(s)); return intToRGB(hashCode(s));
} }
function getContrastYIQ(hexcolor){
var r = parseInt(hexcolor.substr(0,2),16);
var g = parseInt(hexcolor.substr(2,2),16);
var b = parseInt(hexcolor.substr(4,2),16);
var yiq = ((r*299)+(g*587)+(b*114))/1000;
return (yiq >= 128) ? '000000' : 'ffffff';
}
function setAddShowEvents() { function setAddShowEvents() {
@ -578,9 +586,11 @@ function setAddShowEvents() {
} }
var bgColorEle = $("#add_show_background_color"); var bgColorEle = $("#add_show_background_color");
var textColorEle = $("#add_show_color");
$('#add_show_name').bind('input', 'change', function(){ $('#add_show_name').bind('input', 'change', function(){
var colorCode = stringToColor($(this).val()); var colorCode = stringToColor($(this).val());
bgColorEle.val(colorCode); bgColorEle.val(colorCode);
textColorEle.val(getContrastYIQ(colorCode));
}); });
} }

View file

@ -132,7 +132,7 @@ function findViewportDimensions() {
return { return {
width: viewportwidth, width: viewportwidth,
height: viewportheight height: viewportheight-45
}; };
} }

View file

@ -1136,13 +1136,11 @@ var AIRTIME = (function(AIRTIME){
if (oItems.del !== undefined) { if (oItems.del !== undefined) {
callback = function() { callback = function() {
if (confirm("Delete selected item?")) {
AIRTIME.showbuilder.fnRemove([{ AIRTIME.showbuilder.fnRemove([{
id: data.id, id: data.id,
timestamp: data.timestamp, timestamp: data.timestamp,
instance: data.instance instance: data.instance
}]); }]);
}
}; };
oItems.del.callback = callback; oItems.del.callback = callback;

View file

@ -107,12 +107,28 @@ echo "* Making sure /etc/default/locale is set properly"
set +e set +e
update-locale update-locale
cat /etc/default/locale | grep -i "LANG=.*UTF-\?8" cat /etc/default/locale | grep -i "LANG=.*UTF-\?8"
set -e
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
echo "non UTF-8 default locale found in /etc/default/locale." echo -e " * Fail\n"
echo "A non UTF-8 default locale found in /etc/default/locale. Airtime requires
a UTF-8 locale to run. To fix this please do the following:
Ubuntu:
Put line 'en_US.UTF-8 UTF-8' (or similar) without quotes to '/var/lib/locales/supported.d/local',
replacing any existing lines.
A list of supported locales is available in '/usr/share/i18n/SUPPORTED'
Then run 'sudo dpkg-reconfigure locales'
Debian:
Run 'sudo dpkg-reconfigure locales' and use the interface to select 'en_US.UTF-8 UTF-8' (or similar).
On the second page select this new locale as the default.
After these changes have been made simply run install again.
Now exiting install...
"
exit 1 exit 1
fi fi
set -e
# Check if airtime exists already # Check if airtime exists already
set +e set +e
@ -133,13 +149,14 @@ if [ "$result" -eq "0" ]; then
rm -f "/etc/airtime/media-monitor.cfg" rm -f "/etc/airtime/media-monitor.cfg"
rm -f "/etc/airtime/pypo.cfg" rm -f "/etc/airtime/pypo.cfg"
elif [ "$result" -eq "1" -a "$reinstall" = "f" ]; then elif [ "$result" -eq "1" -a "$reinstall" = "f" ]; then
echo " * Same version of Airtime already installed!" echo " * Same version of Airtime already installed! Reusing database."
exit 1; nodb='t'
overwrite='f'
elif [ "$result" -eq "2" ]; then elif [ "$result" -eq "2" ]; then
echo " * Previous version of Airtime already installed..will perform upgrade" echo " * Previous version of Airtime already installed..will perform upgrade."
DO_UPGRADE="1" DO_UPGRADE="1"
elif [ "$result" -eq "3" ]; then elif [ "$result" -eq "3" ]; then
echo " * You require at least Airtime 1.8.0 installed for upgrade" echo " * You require at least Airtime 1.8.0 installed for upgrade."
exit 1 exit 1
fi fi

View file

@ -6,6 +6,28 @@ if [[ $EUID -ne 0 ]]; then
exit 1 exit 1
fi fi
options=$(getopt -o p -l purge -- "$@")
if [ $? -ne 0 ]; then
echo "only -p or --purge parameter allowed"
exit 1
fi
eval set -- "$options"
purge='f'
while true
do
case "$1" in
-p|--purge) purge='t'; shift;;
--) shift 1; break ;;
*) break ;;
esac
done
#Make 'purge' env variable available to sub bash script
export purge
echo -e "\n******************************* Uninstall Begin ********************************" echo -e "\n******************************* Uninstall Begin ********************************"
# Absolute path to this script, e.g. /home/user/bin/foo.sh # Absolute path to this script, e.g. /home/user/bin/foo.sh

View file

@ -19,7 +19,6 @@ set +e
monit unmonitor airtime-media-monitor >/dev/null 2>&1 monit unmonitor airtime-media-monitor >/dev/null 2>&1
monit unmonitor airtime-liquidsoap >/dev/null 2>&1 monit unmonitor airtime-liquidsoap >/dev/null 2>&1
monit unmonitor airtime-playout >/dev/null 2>&1 monit unmonitor airtime-playout >/dev/null 2>&1
#monit unmonitor airtime-show-recorder >/dev/null 2>&1
monit unmonitor rabbitmq-server monit unmonitor rabbitmq-server
set -e set -e
@ -31,5 +30,7 @@ python $AIRTIMEROOT/python_apps/pypo/install/pypo-uninitialize.py
python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-uninitialize.py python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-uninitialize.py
#python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-uninitialize.py #python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-uninitialize.py
if [ "$purge" = "t" ]; then
#call Airtime uninstall script #call Airtime uninstall script
php --php-ini ${SCRIPTPATH}/../airtime-php.ini ${SCRIPTPATH}/airtime-uninstall.php php --php-ini ${SCRIPTPATH}/../airtime-php.ini ${SCRIPTPATH}/airtime-uninstall.php
fi

View file

@ -39,7 +39,7 @@ def convert_dict_value_to_utf8(md):
# Airtime API Client # Airtime API Client
################################################################################ ################################################################################
class AirTimeApiClient(): class AirtimeApiClient():
def __init__(self, logger=None): def __init__(self, logger=None):
if logger is None: if logger is None:
@ -437,10 +437,14 @@ class AirTimeApiClient():
response = self.get_response_from_server(url) response = self.get_response_from_server(url)
response = json.loads(response) response = json.loads(response)
except Exception, e: except Exception, e:
response = None response = {}
logger.error("Exception: %s", e) logger.error("Exception: %s", e)
return response try:
return response["files"]
except KeyError:
self.logger.error("Could not find index 'files' in dictionary: %s", str(response))
return []
def list_all_watched_dirs(self): def list_all_watched_dirs(self):
logger = self.logger logger = self.logger

View file

@ -40,8 +40,7 @@ class AirtimeMediaMonitorBootstrap():
went offline. went offline.
""" """
def scan(self): def scan(self):
directories = self.get_list_of_watched_dirs(); directories = self.get_list_of_watched_dirs()
self.logger.info("watched directories found: %s", directories) self.logger.info("watched directories found: %s", directories)
for id, dir in directories.iteritems(): for id, dir in directories.iteritems():
@ -57,12 +56,21 @@ class AirtimeMediaMonitorBootstrap():
return self.api_client.list_all_db_files(dir_id) return self.api_client.list_all_db_files(dir_id)
""" """
returns the path and the database row id for this path for all watched directories. Also returns the path and its corresponding database row idfor all watched directories. Also
returns the Stor directory, which can be identified by its row id (always has value of "1") returns the Stor directory, which can be identified by its row id (always has value of "1")
Return type is a dictionary similar to:
{"1":"/srv/airtime/stor/"}
""" """
def get_list_of_watched_dirs(self): def get_list_of_watched_dirs(self):
json = self.api_client.list_all_watched_dirs() json = self.api_client.list_all_watched_dirs()
try:
return json["dirs"] return json["dirs"]
except KeyError as e:
self.logger.error("Could not find index 'dirs' in dictionary: %s", str(json))
self.logger.error(e)
return {}
""" """
This function takes in a path name provided by the database (and its corresponding row id) This function takes in a path name provided by the database (and its corresponding row id)
@ -86,8 +94,9 @@ class AirtimeMediaMonitorBootstrap():
db_known_files_set = set() db_known_files_set = set()
files = self.list_db_files(dir_id) files = self.list_db_files(dir_id)
for file in files['files']:
db_known_files_set.add(file) for f in files:
db_known_files_set.add(f)
all_files = self.mmc.clean_dirty_file_paths( self.mmc.scan_dir_for_new_files(dir) ) all_files = self.mmc.clean_dirty_file_paths( self.mmc.scan_dir_for_new_files(dir) )
@ -111,10 +120,9 @@ class AirtimeMediaMonitorBootstrap():
stdout = self.mmc.exec_command(command) stdout = self.mmc.exec_command(command)
if stdout is None: if stdout is None:
self.logger.error("Unrecoverable error when syncing db to filesystem.") new_files = []
return else:
new_files = stdout.splitlines()
new_files = self.mmc.clean_dirty_file_paths(stdout.splitlines())
new_and_modified_files = set() new_and_modified_files = set()
for file_path in new_files: for file_path in new_files:

View file

@ -12,8 +12,17 @@ import traceback
""" """
list of supported easy tags in mutagen version 1.20 list of supported easy tags in mutagen version 1.20
['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry', 'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby', 'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid', 'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort', 'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor', 'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid', 'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid', 'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid', 'arranger', 'albumsort', 'replaygain_*_peak', 'organization'] ['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry',
'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby',
'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid',
'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort',
'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor',
'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid',
'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid',
'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid',
'arranger', 'albumsort', 'replaygain_*_peak', 'organization']
""" """
class AirtimeMetadata: class AirtimeMetadata:
def __init__(self): def __init__(self):
@ -57,10 +66,17 @@ class AirtimeMetadata:
self.logger = logging.getLogger() self.logger = logging.getLogger()
def get_md5(self, filepath): def get_md5(self, filepath):
"""
Returns an md5 of the file located at filepath. Returns an empty string
if there was an error reading the file.
"""
try:
f = open(filepath, 'rb') f = open(filepath, 'rb')
m = hashlib.md5() m = hashlib.md5()
m.update(f.read()) m.update(f.read())
md5 = m.hexdigest() md5 = m.hexdigest()
except Exception, e:
return ""
return md5 return md5
@ -121,6 +137,10 @@ class AirtimeMetadata:
return item return item
def get_md_from_file(self, filepath): def get_md_from_file(self, filepath):
"""
Returns None if error retrieving metadata. Otherwise returns a dictionary
representing the file's metadata
"""
self.logger.info("getting info from filepath %s", filepath) self.logger.info("getting info from filepath %s", filepath)
@ -136,7 +156,6 @@ class AirtimeMetadata:
md['MDATA_KEY_MD5'] = md5 md['MDATA_KEY_MD5'] = md5
file_info = mutagen.File(filepath, easy=True) file_info = mutagen.File(filepath, easy=True)
except Exception, e: except Exception, e:
self.logger.error("failed getting metadata from %s", filepath) self.logger.error("failed getting metadata from %s", filepath)
self.logger.error("Exception %s", e) self.logger.error("Exception %s", e)
@ -146,8 +165,7 @@ class AirtimeMetadata:
#check if file has any metadata #check if file has any metadata
if file_info is None: if file_info is None:
return None return None
#check if file has any metadata
if file_info is not None:
for key in file_info.keys() : for key in file_info.keys() :
if key in self.mutagen2airtime: if key in self.mutagen2airtime:
val = file_info[key] val = file_info[key]
@ -157,7 +175,6 @@ class AirtimeMetadata:
except Exception, e: except Exception, e:
self.logger.error('Exception: %s', e) self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", traceback.format_exc()) self.logger.error("traceback: %s", traceback.format_exc())
if 'MDATA_KEY_TITLE' not in md: if 'MDATA_KEY_TITLE' not in md:
#get rid of file extension from original name, name might have more than 1 '.' in it. #get rid of file extension from original name, name might have more than 1 '.' in it.
original_name = os.path.basename(filepath) original_name = os.path.basename(filepath)
@ -228,18 +245,24 @@ class AirtimeMetadata:
md['MDATA_KEY_COPYRIGHT'] = self.truncate_to_length(md['MDATA_KEY_COPYRIGHT'], 512) md['MDATA_KEY_COPYRIGHT'] = self.truncate_to_length(md['MDATA_KEY_COPYRIGHT'], 512)
#end of db truncation checks. #end of db truncation checks.
md['MDATA_KEY_BITRATE'] = getattr(file_info.info, "bitrate", None) try:
md['MDATA_KEY_SAMPLERATE'] = getattr(file_info.info, "sample_rate", None) md['MDATA_KEY_BITRATE'] = getattr(file_info.info, "bitrate", 0)
self.logger.info("Bitrate: %s , Samplerate: %s", md['MDATA_KEY_BITRATE'], md['MDATA_KEY_SAMPLERATE']) md['MDATA_KEY_SAMPLERATE'] = getattr(file_info.info, "sample_rate", 0)
try: md['MDATA_KEY_DURATION'] = self.format_length(file_info.info.length)
except Exception as e: self.logger.warn("File: '%s' raises: %s", filepath, str(e))
try: md['MDATA_KEY_MIME'] = file_info.mime[0] md['MDATA_KEY_DURATION'] = self.format_length(getattr(file_info.info, "length", 0.0))
except Exception as e: self.logger.warn("File: '%s' has no mime type", filepath, str(e))
md['MDATA_KEY_MIME'] = ""
if len(file_info.mime) > 0:
md['MDATA_KEY_MIME'] = file_info.mime[0]
except Exception as e:
self.logger.warn(e)
if "mp3" in md['MDATA_KEY_MIME']: if "mp3" in md['MDATA_KEY_MIME']:
md['MDATA_KEY_FTYPE'] = "audioclip" md['MDATA_KEY_FTYPE'] = "audioclip"
elif "vorbis" in md['MDATA_KEY_MIME']: elif "vorbis" in md['MDATA_KEY_MIME']:
md['MDATA_KEY_FTYPE'] = "audioclip" md['MDATA_KEY_FTYPE'] = "audioclip"
else:
self.logger.error("File %s of mime type %s does not appear to be a valid vorbis or mp3 file." % (filepath, md['MDATA_KEY_MIME']))
return None
return md return md

View file

@ -36,6 +36,11 @@ class AirtimeNotifier(Notifier):
time.sleep(5) time.sleep(5)
def init_rabbit_mq(self): def init_rabbit_mq(self):
"""
This function will attempt to connect to RabbitMQ Server and if successful
return 'True'. Returns 'False' otherwise.
"""
self.logger.info("Initializing RabbitMQ stuff") self.logger.info("Initializing RabbitMQ stuff")
try: try:
schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True) schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True)

View file

@ -291,6 +291,9 @@ class MediaMonitorCommon:
self.logger.debug(command) self.logger.debug(command)
stdout = self.exec_command(command) stdout = self.exec_command(command)
if stdout is None:
return []
else:
return stdout.splitlines() return stdout.splitlines()
def touch_index_file(self): def touch_index_file(self):

View file

@ -80,7 +80,7 @@ try:
configure_locale() configure_locale()
config = AirtimeMediaConfig(logger) config = AirtimeMediaConfig(logger)
api_client = apc.AirTimeApiClient() api_client = apc.AirtimeApiClient()
api_client.register_component("media-monitor") api_client.register_component("media-monitor")
logger.info("Setting up monitor") logger.info("Setting up monitor")

View file

@ -23,7 +23,7 @@ class ReplayGainUpdater(Thread):
def __init__(self, logger): def __init__(self, logger):
Thread.__init__(self) Thread.__init__(self)
self.logger = logger self.logger = logger
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
def main(self): def main(self):

View file

@ -73,7 +73,7 @@ monit_restart() {
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1 start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
rm -f $PIDFILE1 rm -f $PIDFILE1
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID --make-pidfile --pidfile $PIDFILE0 --startas $DAEMON0 start-stop-daemon --start --background --quiet --chuid $ROOTUSERID:$ROOTUSERID --make-pidfile --pidfile $PIDFILE0 --startas $DAEMON0
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \ start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
--nicelevel -15 --make-pidfile --pidfile $PIDFILE1 --startas $DAEMON1 --nicelevel -15 --make-pidfile --pidfile $PIDFILE1 --startas $DAEMON1

View file

@ -1,6 +1,6 @@
import logging import logging
import sys import sys
from api_clients import api_client from api_clients.api_client import AirtimeApiClient
def generate_liquidsoap_config(ss): def generate_liquidsoap_config(ss):
data = ss['msg'] data = ss['msg']
@ -9,22 +9,22 @@ def generate_liquidsoap_config(ss):
fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n") fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n")
fh.write("################################################\n") fh.write("################################################\n")
for d in data: for d in data:
key = d['keyname']
str_buffer = d[u'keyname'] + " = " str_buffer = d[u'keyname'] + " = "
if(d[u'type'] == 'string'): if(d[u'type'] == 'string'):
temp = d[u'value'] val = '"%s"' % d['value']
str_buffer += '"%s"' % temp
else: else:
temp = d[u'value'] val = d[u'value']
if(temp == ""): val = val if len(val) > 0 else "0"
temp = "0" str_buffer = "%s = %s\n" % (key, val)
str_buffer += temp fh.write(str_buffer.encode('utf-8'))
str_buffer += "\n"
fh.write(api_client.encode_to(str_buffer))
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n') fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
fh.close() fh.close()
logging.basicConfig(format='%(message)s') logging.basicConfig(format='%(message)s')
ac = api_client(logging.getLogger()) ac = AirtimeApiClient(logging.getLogger())
ss = ac.get_stream_setting() ss = ac.get_stream_setting()
if ss is not None: if ss is not None:

View file

@ -1,7 +1,7 @@
from api_clients import * from api_clients import *
import sys import sys
api_clients = api_client.AirTimeApiClient() api_clients = api_client.AirtimeApiClient()
dj_type = sys.argv[1] dj_type = sys.argv[1]
username = sys.argv[2] username = sys.argv[2]

View file

@ -107,10 +107,10 @@ except Exception, e:
class Global: class Global:
def __init__(self): def __init__(self):
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
def selfcheck(self): def selfcheck(self):
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
return self.api_client.is_server_compatible() return self.api_client.is_server_compatible()
def test_api(self): def test_api(self):
@ -172,7 +172,7 @@ if __name__ == '__main__':
g.test_api() g.test_api()
sys.exit() sys.exit()
api_client = api_client.AirTimeApiClient() api_client = api_client.AirtimeApiClient()
api_client.register_component("pypo") api_client.register_component("pypo")
pypoFetch_q = Queue() pypoFetch_q = Queue()

View file

@ -40,7 +40,7 @@ except Exception, e:
class PypoFetch(Thread): class PypoFetch(Thread):
def __init__(self, pypoFetch_q, pypoPush_q, media_q, telnet_lock): def __init__(self, pypoFetch_q, pypoPush_q, media_q, telnet_lock):
Thread.__init__(self) Thread.__init__(self)
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
self.fetch_queue = pypoFetch_q self.fetch_queue = pypoFetch_q
self.push_queue = pypoPush_q self.push_queue = pypoPush_q
self.media_prepare_queue = media_q self.media_prepare_queue = media_q

View file

@ -64,7 +64,7 @@ except Exception, e:
class Notify: class Notify:
def __init__(self): def __init__(self):
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
def notify_media_start_playing(self, data, media_id): def notify_media_start_playing(self, data, media_id):
logger = logging.getLogger("notify") logger = logging.getLogger("notify")

View file

@ -42,7 +42,7 @@ except Exception, e:
class PypoPush(Thread): class PypoPush(Thread):
def __init__(self, q, telnet_lock): def __init__(self, q, telnet_lock):
Thread.__init__(self) Thread.__init__(self)
self.api_client = api_client.AirTimeApiClient() self.api_client = api_client.AirtimeApiClient()
self.queue = q self.queue = q
self.telnet_lock = telnet_lock self.telnet_lock = telnet_lock

View file

@ -25,6 +25,8 @@ def printUsage():
print " -u user (default: source) " print " -u user (default: source) "
print " -p password (default: hackme) " print " -p password (default: hackme) "
print " -m mount (default: test) " print " -m mount (default: test) "
print " -h show help menu"
def find_liquidsoap_binary(): def find_liquidsoap_binary():
""" """

View file

@ -1,4 +1,4 @@
var AIRTIME_API_VERSION = "1.0"; var AIRTIME_API_VERSION = "1.1";
(function($){ (function($){
$.fn.airtimeShowSchedule = function(options) { $.fn.airtimeShowSchedule = function(options) {
@ -6,7 +6,8 @@
var defaults = { var defaults = {
updatePeriod: 20, //seconds updatePeriod: 20, //seconds
sourceDomain: "http://localhost/", //where to get show status from sourceDomain: "http://localhost/", //where to get show status from
text: {onAirToday:"On air today"} text: {onAirToday:"On air today"},
showLimit: 5
}; };
options = $.extend(true, defaults, options); options = $.extend(true, defaults, options);
options.sourceDomain = addEndingBackslash(options.sourceDomain); options.sourceDomain = addEndingBackslash(options.sourceDomain);
@ -56,7 +57,7 @@
function getServerData(){ function getServerData(){
$.ajax({url: options.sourceDomain + "api/live-info/", $.ajax({url: options.sourceDomain + "api/live-info/",
data: {type:"endofday",limit:"5"}, data: {type:"endofday",limit: options.showLimit},
dataType: "jsonp", dataType: "jsonp",
success:function(data) { success:function(data) {
processData(data); processData(data);

View file

@ -17,7 +17,8 @@ $(document).ready(function() {
$("#onAirToday").airtimeShowSchedule({ $("#onAirToday").airtimeShowSchedule({
sourceDomain: "http://localhost", sourceDomain: "http://localhost",
text: {onAirToday:"On air today"}, text: {onAirToday:"On air today"},
updatePeriod: 5 //seconds updatePeriod: 5, //seconds
showLimit: 10
}); });
$("#scheduleTabs").airtimeWeekSchedule({ $("#scheduleTabs").airtimeWeekSchedule({
sourceDomain:"http://localhost", sourceDomain:"http://localhost",