Merge branch '2.1.x' into devel

Conflicts:
	airtime_mvc/application/controllers/ApiController.php
	airtime_mvc/application/controllers/LibraryController.php
	airtime_mvc/application/controllers/PlaylistController.php
	airtime_mvc/application/models/Playlist.php
	python_apps/media-monitor/airtimefilemonitor/airtimemediamonitorbootstrap.py
	python_apps/media-monitor/airtimefilemonitor/airtimemetadata.py
This commit is contained in:
Martin Konecny 2012-07-16 14:31:03 -04:00
commit 4ebcb1b1f9
23 changed files with 233 additions and 124 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

@ -261,30 +261,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 $limit = $request->getParam('limit');
if($limit == "" || !is_numeric($limit)) {
$limit = "5";
}
// make GetNextShows use end of day
$utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc(); $utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc();
$result = array("env"=>APPLICATION_ENV, $result = array("env"=>APPLICATION_ENV,
"schedulerTime"=>gmdate("Y-m-d H:i:s"), "schedulerTime"=>gmdate("Y-m-d H:i:s"),
"nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, 5, $utcTimeEnd)); "nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd));
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"));
} else { } else {
$limit = $request->getParam('limit');
if ($limit == "" || !is_numeric($limit)) {
$limit = "5";
}
$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();
} }
@ -95,6 +95,10 @@ class PlaylistController extends Zend_Controller_Action
$this->changePlaylist(null); $this->changePlaylist(null);
$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)
{ {
@ -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);
$this->view->pl = $pl; $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;
}
$formatter = new LengthFormatter($pl->getLength()); $formatter = new LengthFormatter($pl->getLength());
$this->view->length = $formatter->format(); $this->view->length = $formatter->format();
@ -186,6 +196,9 @@ class PlaylistController extends Zend_Controller_Action
$ids = $this->_getParam('ids'); $ids = $this->_getParam('ids');
$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 {
@ -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

@ -453,13 +453,14 @@ class Application_Model_Playlist
->filterByDbPlaylistId($this->id) ->filterByDbPlaylistId($this->id)
->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); }
}
/** /**
* Change fadeIn and fadeOut values for playlist Element * Change fadeIn and fadeOut values for playlist Element
@ -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)
{ {
CcPlaylistQuery::create()->findPKs($p_ids)->delete(); $leftOver = self::playlistsNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
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

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

@ -362,10 +362,10 @@ class AirTimeApiClient():
return response return response
#returns a list of all db files for a given directory in JSON format: # returns a list of all db files for a given directory in JSON format:
#{"files":["path/to/file1", "path/to/file2"]} # ["path/to/file1", "path/to/file2"]
#Note that these are relative paths to the given directory. The full # Note that these are relative paths to the given directory. The full
#path is not returned. # path is not returned.
def list_all_db_files(self, dir_id): def list_all_db_files(self, dir_id):
logger = self.logger logger = self.logger
try: try:
@ -377,10 +377,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()
return json["dirs"]
try:
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):
f = open(filepath, 'rb') """
m = hashlib.md5() Returns an md5 of the file located at filepath. Returns an empty string
m.update(f.read()) if there was an error reading the file.
md5 = m.hexdigest() """
try:
f = open(filepath, 'rb')
m = hashlib.md5()
m.update(f.read())
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,18 +165,16 @@ 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() :
if key in self.mutagen2airtime:
val = file_info[key]
try:
if val is not None and len(val) > 0 and val[0] is not None and len(val[0]) > 0:
md[self.mutagen2airtime[key]] = val[0]
except Exception, e:
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", traceback.format_exc())
for key in file_info.keys() :
if key in self.mutagen2airtime:
val = file_info[key]
try:
if val is not None and len(val) > 0 and val[0] is not None and len(val[0]) > 0:
md[self.mutagen2airtime[key]] = val[0]
except Exception, e:
self.logger.error('Exception: %s', e)
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)) md['MDATA_KEY_DURATION'] = self.format_length(getattr(file_info.info, "length", 0.0))
try: md['MDATA_KEY_MIME'] = file_info.mime[0] md['MDATA_KEY_MIME'] = ""
except Exception as e: self.logger.warn("File: '%s' has no mime type", filepath, str(e)) 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

@ -292,7 +292,10 @@ class MediaMonitorCommon:
self.logger.debug(command) self.logger.debug(command)
stdout = self.exec_command(command) stdout = self.exec_command(command)
return stdout.splitlines() if stdout is None:
return []
else:
return stdout.splitlines()
def touch_index_file(self): def touch_index_file(self):
dirname = os.path.dirname(self.timestamp_file) dirname = os.path.dirname(self.timestamp_file)

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

@ -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",