CC-3346: Recorder: Merge recorder with pypo

- Pypo fech works as msg listner for recroder now.
- recorder is part of pypo and all it does is waiting for msg from pypo
fetch and spwan a show recorder thread.
- added new parameter logger to api client. This way apiclient will log
into specific log file instead of grabbing current log file.
- show recoder is removed from all check system/status page
This commit is contained in:
James 2012-02-24 13:12:50 -05:00
parent 2ef6d230f9
commit 2f689ed583
30 changed files with 419 additions and 856 deletions

View File

@ -775,7 +775,6 @@ class ApiController extends Zend_Controller_Action
"rabbitmq"=>Application_Model_Systemstatus::GetRabbitMqStatus(),
"pypo"=>Application_Model_Systemstatus::GetPypoStatus(),
"liquidsoap"=>Application_Model_Systemstatus::GetLiquidsoapStatus(),
"show_recorder"=>Application_Model_Systemstatus::GetShowRecorderStatus(),
"media_monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus()
)
);

View File

@ -21,10 +21,6 @@ class SystemstatusController extends Zend_Controller_Action
"media-monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus(),
"rabbitmq-server"=>Application_Model_Systemstatus::GetRabbitMqStatus()
);
if (!isset($_SERVER["AIRTIME_SRV"])){
$services["show-recorder"]=Application_Model_Systemstatus::GetShowRecorderStatus();
}
$partitions = Application_Model_Systemstatus::GetDiskInfo();
@ -32,36 +28,4 @@ class SystemstatusController extends Zend_Controller_Action
$this->view->status->services = $services;
$this->view->status->partitions = $partitions;
}
public function getLogFileAction()
{
$log_files = array("pypo"=>"/var/log/airtime/pypo/pypo.log",
"liquidsoap"=>"/var/log/airtime/pypo-liquidsoap/ls_script.log",
"media-monitor"=>"/var/log/airtime/media-monitor/media-monitor.log",
"show-recorder"=>"/var/log/airtime/show-recorder/show-recorder.log",
"icecast2"=>"/var/log/icecast2/error.log");
$id = $this->_getParam('id');
Logging::log($id);
if (array_key_exists($id, $log_files)){
$filepath = $log_files[$id];
$filename = basename($filepath);
header("Content-Disposition: attachment; filename=$filename");
header("Content-Length: " . filesize($filepath));
// !! binary mode !!
$fp = fopen($filepath, 'rb');
//We can have multiple levels of output buffering. Need to
//keep looping until all have been disabled!!!
//http://www.php.net/manual/en/function.ob-end-flush.php
while (@ob_end_flush());
fpassthru($fp);
fclose($fp);
//make sure to exit here so that no other output is sent.
exit;
}
}
}

View File

@ -8,7 +8,7 @@ class RabbitMqPlugin extends Zend_Controller_Plugin_Abstract
$md = array('schedule' => Application_Model_Schedule::GetScheduledPlaylists());
Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md);
if (!isset($_SERVER['AIRTIME_SRV'])){
Application_Model_RabbitMq::SendMessageToShowRecorder("update_schedule");
Application_Model_RabbitMq::SendMessageToShowRecorder("update_recorder_schedule");
}
}
}

View File

@ -74,7 +74,7 @@ class Application_Model_RabbitMq
$channel = $conn->channel();
$channel->access_request($CC_CONFIG["rabbitmq"]["vhost"], false, false, true, true);
$EXCHANGE = 'airtime-show-recorder';
$EXCHANGE = 'airtime-pypo';
$channel->exchange_declare($EXCHANGE, 'direct', false, true);
$now = new DateTime("@".time()); //in UTC timezone
@ -82,7 +82,7 @@ class Application_Model_RabbitMq
$temp['event_type'] = $event_type;
$temp['server_timezone'] = Application_Model_Preference::GetTimezone();
if($event_type = "update_schedule"){
if($event_type = "update_recorder_schedule"){
$temp['shows'] = Application_Model_Show::getShows($now, $end_timestamp, $excludeInstance=NULL, $onlyRecord=TRUE);
}
$data = json_encode($temp);

View File

@ -147,21 +147,6 @@ class Application_Model_Systemstatus
}
}
public static function GetShowRecorderStatus(){
$component = CcServiceRegisterQuery::create()->findOneByDbName("show-recorder");
if (is_null($component)){
return null;
} else {
$ip = $component->getDbIp();
$docRoot = self::GetMonitStatus($ip);
$data = self::ExtractServiceInformation($docRoot, "airtime-show-recorder");
return $data;
}
}
public static function GetMediaMonitorStatus(){
$component = CcServiceRegisterQuery::create()->findOneByDbName("media-monitor");

View File

@ -91,14 +91,6 @@ class AirtimeIni
exit(1);
}
if (!copy(__DIR__."/../../python_apps/show-recorder/recorder.cfg", AirtimeIni::CONF_FILE_RECORDER)){
echo "Could not copy recorder.cfg to /etc/airtime/. Exiting.";
exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_RECORDER, self::CONF_PYPO_GRP)){
echo "Could not set ownership of recorder.cfg to 'pypo'. Exiting.";
exit(1);
}
if (!copy(__DIR__."/../../python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg", AirtimeIni::CONF_FILE_LIQUIDSOAP)){
echo "Could not copy liquidsoap.cfg to /etc/airtime/. Exiting.";
exit(1);

View File

@ -429,12 +429,9 @@ class AirtimeInstall
AirtimeIni::CONF_FILE_PYPO,
AirtimeIni::CONF_FILE_RECORDER,
"/usr/lib/airtime/pypo",
"/usr/lib/airtime/show-recorder",
"/var/log/airtime",
"/var/log/airtime/pypo",
"/var/log/airtime/show-recorder",
"/var/tmp/airtime/pypo",
"/var/tmp/airtime/show-recorder");
"/var/tmp/airtime/pypo");
foreach ($dirs as $f) {
if (file_exists($f)) {
echo "+ $f".PHP_EOL;

View File

@ -63,9 +63,9 @@ if [ "$python_service" -eq "0" ]; then
if [ "$pypo" = "t" ]; then
python $AIRTIMEROOT/python_apps/pypo/install/pypo-copy-files.py
fi
if [ "$showrecorder" = "t" ]; then
python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-copy-files.py
fi
#if [ "$showrecorder" = "t" ]; then
# python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-copy-files.py
#fi
fi
mkdir -p /usr/lib/airtime

View File

@ -36,9 +36,9 @@ fi
if [ "$pypo" = "t" ]; then
python $AIRTIMEROOT/python_apps/pypo/install/pypo-initialize.py
fi
if [ "$showrecorder" = "t" ]; then
python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-initialize.py
fi
#if [ "$showrecorder" = "t" ]; then
# python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-initialize.py
#fi
# Start monit if it is not running, or restart if it is.
@ -61,9 +61,9 @@ if [ "$disable_auto_start_services" = "f" ]; then
monit monitor airtime-playout
monit monitor airtime-liquidsoap
fi
if [ "$showrecorder" = "t" ]; then
monit monitor airtime-show-recorder
fi
# if [ "$showrecorder" = "t" ]; then
# monit monitor airtime-show-recorder
# fi
fi
monit monitor rabbitmq-server

View File

@ -38,8 +38,8 @@ echo "* Pypo"
python $AIRTIMEROOT/python_apps/pypo/install/pypo-remove-files.py
echo "* Media-Monitor"
python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-remove-files.py
echo "* Show-Recorder"
python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-remove-files.py
#echo "* Show-Recorder"
#python $AIRTIMEROOT/python_apps/show-recorder/install/recorder-remove-files.py
#remove symlinks
rm -f /usr/bin/airtime-import

View File

@ -19,8 +19,8 @@ set +e
monit unmonitor airtime-media-monitor >/dev/null 2>&1
monit unmonitor airtime-liquidsoap >/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 airtime-show-recorder >/dev/null 2>&1
monit unmonitor rabbitmq-server
set -e
#virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
@ -29,7 +29,7 @@ set -e
#uninitialize Airtime services
python $AIRTIMEROOT/python_apps/pypo/install/pypo-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
#call Airtime uninstall script
php --php-ini ${SCRIPTPATH}/../airtime-php.ini ${SCRIPTPATH}/airtime-uninstall.php

View File

@ -24,14 +24,17 @@ import string
AIRTIME_VERSION = "2.1.0"
def api_client_factory(config):
logger = logging.getLogger()
def api_client_factory(config, logger=None):
if logger != None:
temp_logger = logger
else:
temp_logger = logging.getLogger()
if config["api_client"] == "airtime":
return AirTimeApiClient()
return AirTimeApiClient(temp_logger)
elif config["api_client"] == "obp":
return ObpApiClient()
else:
logger.info('API Client "'+config["api_client"]+'" not supported. Please check your config file.\n')
temp_logger.info('API Client "'+config["api_client"]+'" not supported. Please check your config file.\n')
sys.exit()
def to_unicode(obj, encoding='utf-8'):
@ -161,17 +164,20 @@ class ApiClientInterface:
class AirTimeApiClient(ApiClientInterface):
def __init__(self):
def __init__(self, logger=None):
if logger != None:
self.logger = logger
else:
self.logger = logging.getLogger()
# loading config file
try:
self.config = ConfigObj('/etc/airtime/api_client.cfg')
except Exception, e:
logger = logging.getLogger()
logger.error('Error loading config file: %s', e)
self.logger.error('Error loading config file: %s', e)
sys.exit(1)
def get_response_from_server(self, url):
logger = logging.getLogger()
logger = self.logger
successful_response = False
while not successful_response:
@ -191,7 +197,7 @@ class AirTimeApiClient(ApiClientInterface):
def __get_airtime_version(self, verbose = True):
logger = logging.getLogger()
logger = self.logger
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["version_url"])
logger.debug("Trying to contact %s", url)
url = url.replace("%%api_key%%", self.config["api_key"])
@ -211,7 +217,7 @@ class AirTimeApiClient(ApiClientInterface):
return version
def test(self):
logger = logging.getLogger()
logger = self.logger
status, items = self.get_schedule('2010-01-01-00-00-00', '2011-01-01-00-00-00')
schedule = items["playlists"]
logger.debug("Number of playlists found: %s", str(len(schedule)))
@ -227,7 +233,7 @@ class AirTimeApiClient(ApiClientInterface):
def is_server_compatible(self, verbose = True):
logger = logging.getLogger()
logger = self.logger
version = self.__get_airtime_version(verbose)
if (version == -1):
if (verbose):
@ -246,7 +252,7 @@ class AirTimeApiClient(ApiClientInterface):
def get_schedule(self, start=None, end=None):
logger = logging.getLogger()
logger = self.logger
# Construct the URL
export_url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["export_url"])
@ -267,7 +273,7 @@ class AirTimeApiClient(ApiClientInterface):
def get_media(self, uri, dst):
logger = logging.getLogger()
logger = self.logger
try:
src = uri + "/api_key/%%api_key%%"
@ -284,7 +290,7 @@ class AirTimeApiClient(ApiClientInterface):
Tell server that the scheduled *playlist* has started.
"""
def notify_scheduled_item_start_playing(self, pkey, schedule):
logger = logging.getLogger()
logger = self.logger
playlist = schedule[pkey]
schedule_id = playlist["schedule_id"]
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_item_url"])
@ -311,7 +317,7 @@ class AirTimeApiClient(ApiClientInterface):
liquidsoap in get_liquidsoap_data().
"""
def notify_media_item_start_playing(self, data, media_id):
logger = logging.getLogger()
logger = self.logger
response = ''
try:
schedule_id = data
@ -331,7 +337,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def get_liquidsoap_data(self, pkey, schedule):
logger = logging.getLogger()
logger = self.logger
playlist = schedule[pkey]
data = dict()
try:
@ -341,13 +347,12 @@ class AirTimeApiClient(ApiClientInterface):
return data
def get_shows_to_record(self):
logger = logging.getLogger()
logger = self.logger
response = None
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["show_schedule_url"])
logger.debug(url)
url = url.replace("%%api_key%%", self.config["api_key"])
response = self.get_response_from_server(url)
response = json.loads(response)
@ -360,7 +365,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def upload_recorded_show(self, data, headers):
logger = logging.getLogger()
logger = self.logger
response = ''
retries = int(self.config["upload_retries"])
@ -394,7 +399,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def setup_media_monitor(self):
logger = logging.getLogger()
logger = self.logger
response = None
try:
@ -411,7 +416,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def update_media_metadata(self, md, mode, is_record=False):
logger = logging.getLogger()
logger = self.logger
response = None
try:
@ -456,7 +461,7 @@ class AirTimeApiClient(ApiClientInterface):
#Note that these are relative paths to the given directory. The full
#path is not returned.
def list_all_db_files(self, dir_id):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_db_files"])
@ -473,7 +478,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def list_all_watched_dirs(self):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_watched_dirs"])
@ -489,7 +494,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def add_watched_dir(self, path):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["add_watched_dir"])
@ -506,7 +511,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def remove_watched_dir(self, path):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["remove_watched_dir"])
@ -523,7 +528,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def set_storage_dir(self, path):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["set_storage_dir"])
@ -540,7 +545,7 @@ class AirTimeApiClient(ApiClientInterface):
return response
def get_stream_setting(self):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["get_stream_setting"])
@ -561,7 +566,7 @@ class AirTimeApiClient(ApiClientInterface):
via a http server.
"""
def register_component(self, component):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["register_component"])
@ -573,7 +578,7 @@ class AirTimeApiClient(ApiClientInterface):
logger.error("Exception: %s", e)
def notify_liquidsoap_status(self, msg, stream_id, time):
logger = logging.getLogger()
logger = self.logger
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_liquidsoap_status"])

View File

@ -60,6 +60,8 @@ try:
create_dir(config['cache_dir'])
create_dir(config['file_dir'])
create_dir(config['tmp_dir'])
create_dir(config["base_recorded_files"])
#copy files to bin dir
copy_dir("%s/.."%current_script_dir, config["bin_dir"]+"/bin/")
@ -72,6 +74,7 @@ try:
os.system("chmod 755 "+os.path.join(config["bin_dir"], "bin/liquidsoap_scripts/notify.sh"))
os.system("chown -R pypo:pypo "+config["bin_dir"])
os.system("chown -R pypo:pypo "+config["cache_base_dir"])
os.system("chown -R pypo:pypo "+config["base_recorded_files"])
#copy init.d script
shutil.copy(config["bin_dir"]+"/bin/airtime-playout-init-d", "/etc/init.d/airtime-playout")

View File

@ -1,34 +1,46 @@
[loggers]
keys=root,fetch,push
keys=root,fetch,push,recorder
[handlers]
keys=fileOutHandler
keys=pypo,recorder
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=fileOutHandler
handlers=pypo
[logger_fetch]
level=DEBUG
handlers=fileOutHandler
handlers=pypo
qualname=fetch
propagate=0
[logger_push]
level=DEBUG
handlers=fileOutHandler
handlers=pypo
qualname=push
propagate=0
[handler_fileOutHandler]
[logger_recorder]
level=DEBUG
handlers=recorder
qualname=recorder
propagate=0
[handler_pypo]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=("/var/log/airtime/pypo/pypo.log", 'a', 1000000, 5,)
[handler_recorder]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=("/var/log/airtime/pypo/show-recorder.log", 'a', 1000000, 5,)
[formatter_simpleFormatter]
format=%(asctime)s %(levelname)s - [%(filename)s : %(funcName)s() : line %(lineno)d] - %(message)s
datefmt=

View File

@ -15,6 +15,7 @@ from Queue import Queue
from pypopush import PypoPush
from pypofetch import PypoFetch
from recorder import Recorder
from configobj import ConfigObj
@ -127,12 +128,18 @@ if __name__ == '__main__':
api_client.register_component("pypo")
q = Queue()
recorder_q = Queue()
pp = PypoPush(q)
pp.daemon = True
pp.start()
pf = PypoFetch(q)
recorder = Recorder(recorder_q)
recorder.daemon = True
recorder.start()
pf = PypoFetch(q, recorder_q)
pf.daemon = True
pf.start()

View File

@ -71,3 +71,17 @@ push_interval = 1 # in seconds
# while 'otf' (on the fly) cues while loading into ls
# (needs the post_processor patch)
cue_style = 'pre'
############################################
# Recorded Audio settings #
############################################
record_bitrate = 256
record_samplerate = 44100
record_channels = 2
record_sample_size = 16
#can be either ogg|mp3, mp3 recording requires installation of the package "lame"
record_file_type = 'ogg'
# base path to store recordered shows at
base_recorded_files = '/var/tmp/airtime/show-recorder/'

View File

@ -42,11 +42,12 @@ except Exception, e:
sys.exit()
class PypoFetch(Thread):
def __init__(self, q):
def __init__(self, q, recorder_q):
Thread.__init__(self)
self.api_client = api_client.api_client_factory(config)
self.set_export_source('scheduler')
self.queue = q
self.recorder_queue = recorder_q
self.schedule_data = []
logger = logging.getLogger('fetch')
logger.info("PypoFetch: init complete")
@ -94,6 +95,12 @@ class PypoFetch(Thread):
elif command == 'cancel_current_show':
logger.info("Cancel current show command received...")
self.stop_current_show()
elif command == 'update_recorder_schedule':
temp = m
if temp is not None:
self.parse_shows(temp)
elif command == 'cancel_recording':
self.recorder_queue.put('cancel_recording')
except Exception, e:
logger.error("Exception in handling RabbitMQ message: %s", e)
@ -312,6 +319,30 @@ class PypoFetch(Thread):
# cleanup
try: self.cleanup(self.export_source)
except Exception, e: logger.error("%s", e)
def getDateTimeObj(self,time):
timeinfo = time.split(" ")
date = timeinfo[0].split("-")
time = timeinfo[1].split(":")
date = map(int, date)
time = map(int, time)
return datetime(date[0], date[1], date[2], time[0], time[1], time[2], 0, None)
def parse_shows(self, m):
logger = logging.getLogger('fetch')
logger.info("Parsing recording show schedules...")
shows_to_record = {}
shows = m['shows']
for show in shows:
show_starts = self.getDateTimeObj(show[u'starts'])
show_end = self.getDateTimeObj(show[u'ends'])
time_delta = show_end - show_starts
shows_to_record[show[u'starts']] = [time_delta, show[u'instance_id'], show[u'name'], m['server_timezone']]
self.recorder_queue.put(shows_to_record)
logger.info(shows_to_record)
"""
@ -487,6 +518,17 @@ class PypoFetch(Thread):
if status == 1:
logger.info("Bootstrap schedule received: %s", self.schedule_data)
self.process_schedule(self.schedule_data, "scheduler", True)
# Bootstrap: since we are just starting up, we need to grab the
# most recent schedule. After that we can just wait for updates.
try:
temp = self.api_client.get_shows_to_record()
if temp is not None:
self.parse_shows(temp)
logger.info("Bootstrap recorder schedule received: %s", temp)
except Exception, e:
logger.error(e)
logger.info("Bootstrap complete: got initial copy of the schedule")
@ -515,8 +557,18 @@ class PypoFetch(Thread):
status, self.schedule_data = self.api_client.get_schedule()
if status == 1:
self.process_schedule(self.schedule_data, "scheduler", False)
"""
Fetch recorder schedule
"""
try:
temp = self.api_client.get_shows_to_record()
if temp is not None:
self.parse_shows(temp)
logger.info("updated recorder schedule received: %s", temp)
except Exception, e:
logger.error(e)
loops += 1
loops += 1
"""
Main loop of the thread:

View File

@ -0,0 +1,270 @@
import urllib
import logging
import logging.config
import json
import time
import datetime
import os
import sys
import shutil
import socket
import pytz
import signal
import math
from configobj import ConfigObj
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
from subprocess import Popen
from threading import Thread
import mutagen
from api_clients import api_client
# For RabbitMQ
from kombu.connection import BrokerConnection
from kombu.messaging import Exchange, Queue, Consumer, Producer
# loading config file
try:
config = ConfigObj('/etc/airtime/pypo.cfg')
except Exception, e:
self.logger.error('Error loading config file: %s', e)
sys.exit()
def getDateTimeObj(time):
timeinfo = time.split(" ")
date = timeinfo[0].split("-")
time = timeinfo[1].split(":")
date = map(int, date)
time = map(int, time)
return datetime.datetime(date[0], date[1], date[2], time[0], time[1], time[2], 0, None)
PUSH_INTERVAL = 2
class ShowRecorder(Thread):
def __init__ (self, show_instance, show_name, filelength, start_time):
Thread.__init__(self)
self.logger = logging.getLogger('recorder')
self.api_client = api_client.api_client_factory(config, self.logger)
self.filelength = filelength
self.start_time = start_time
self.show_instance = show_instance
self.show_name = show_name
self.p = None
def record_show(self):
length = str(self.filelength)+".0"
filename = self.start_time
filename = filename.replace(" ", "-")
if config["record_file_type"] in ["mp3", "ogg"]:
filetype = config["record_file_type"]
else:
filetype = "ogg";
filepath = "%s%s.%s" % (config["base_recorded_files"], filename, filetype)
br = config["record_bitrate"]
sr = config["record_samplerate"]
c = config["record_channels"]
ss = config["record_sample_size"]
#-f:16,2,44100
#-b:256
command = "ecasound -f:%s,%s,%s -i alsa -o %s,%s000 -t:%s" % (ss, c, sr, filepath, br, length)
args = command.split(" ")
self.logger.info("starting record")
self.logger.info("command " + command)
self.p = Popen(args)
#blocks at the following line until the child process
#quits
code = self.p.wait()
self.logger.info("finishing record, return code %s", self.p.returncode)
code = self.p.returncode
self.p = None
return code, filepath
def cancel_recording(self):
#add 3 second delay before actually cancelling the show. The reason
#for this is because it appears that ecasound starts 1 second later than
#it should, and therefore this method is sometimes incorrectly called 1
#second before the show ends.
#time.sleep(3)
#send signal interrupt (2)
self.logger.info("Show manually cancelled!")
if (self.p is not None):
self.p.send_signal(signal.SIGINT)
#if self.p is defined, then the child process ecasound is recording
def is_recording(self):
return (self.p is not None)
def upload_file(self, filepath):
filename = os.path.split(filepath)[1]
# Register the streaming http handlers with urllib2
register_openers()
# headers contains the necessary Content-Type and Content-Length
# datagen is a generator object that yields the encoded parameters
datagen, headers = multipart_encode({"file": open(filepath, "rb"), 'name': filename, 'show_instance': self.show_instance})
self.api_client.upload_recorded_show(datagen, headers)
def set_metadata_and_save(self, filepath):
try:
date = self.start_time
md = date.split(" ")
time = md[1].replace(":", "-")
self.logger.info("time: %s" % time)
name = time+"-"+self.show_name
artist = api_client.encode_to("Airtime Show Recorder",'utf-8')
#set some metadata for our file daemon
recorded_file = mutagen.File(filepath, easy=True)
recorded_file['title'] = name
recorded_file['artist'] = artist
recorded_file['date'] = md[0]
recorded_file['tracknumber'] = self.show_instance
recorded_file.save()
except Exception, e:
self.logger.error("Exception: %s", e)
def run(self):
code, filepath = self.record_show()
if code == 0:
try:
self.logger.info("Preparing to upload %s" % filepath)
self.set_metadata_and_save(filepath)
self.upload_file(filepath)
os.remove(filepath)
except Exception, e:
self.logger.error(e)
else:
self.logger.info("problem recording show")
os.remove(filepath)
class Recorder(Thread):
def __init__(self, q):
Thread.__init__(self)
self.logger = logging.getLogger('recorder')
self.api_client = api_client.api_client_factory(config)
self.api_client.register_component("show-recorder")
self.sr = None
self.shows_to_record = {}
self.server_timezone = ''
self.queue = q
self.logger.info("RecorderFetch: init complete")
def handle_message(self):
if not self.queue.empty():
msg = self.queue.get()
self.logger.info("Receivied msg from Pypo Fetch: %s", msg)
if msg == 'cancel_recording':
if self.sr is not None and self.sr.is_recording():
self.sr.cancel_recording()
else:
self.shows_to_record = msg
if self.shows_to_record:
self.start_record()
def get_time_till_next_show(self):
if len(self.shows_to_record) != 0:
tnow = datetime.datetime.utcnow()
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
next_show = getDateTimeObj(start_time)
delta = next_show - tnow
out = delta.seconds
if out < 5:
self.logger.debug("Shows %s", self.shows_to_record)
self.logger.debug("Next show %s", next_show)
self.logger.debug("Now %s", tnow)
return out
def start_record(self):
if len(self.shows_to_record) != 0:
try:
delta = self.get_time_till_next_show()
if delta < 5:
self.logger.debug("sleeping %s seconds until show", delta)
time.sleep(delta)
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
show_length = self.shows_to_record[start_time][0]
show_instance = self.shows_to_record[start_time][1]
show_name = self.shows_to_record[start_time][2]
server_timezone = self.shows_to_record[start_time][3]
T = pytz.timezone(server_timezone)
start_time_on_UTC = getDateTimeObj(start_time)
start_time_on_server = start_time_on_UTC.replace(tzinfo=pytz.utc).astimezone(T)
start_time_formatted = '%(year)d-%(month)02d-%(day)02d %(hour)02d:%(min)02d:%(sec)02d' % \
{'year': start_time_on_server.year, 'month': start_time_on_server.month, 'day': start_time_on_server.day,\
'hour': start_time_on_server.hour, 'min': start_time_on_server.minute, 'sec': start_time_on_server.second}
self.sr = ShowRecorder(show_instance, show_name, show_length.seconds, start_time_formatted)
self.sr.start()
#remove show from shows to record.
del self.shows_to_record[start_time]
#self.time_till_next_show = self.get_time_till_next_show()
except Exception,e :
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
"""
Main loop of the thread:
Wait for schedule updates from RabbitMQ, but in case there arent any,
poll the server to get the upcoming schedule.
"""
def run(self):
try:
self.logger.info("Started...")
recording = False
loops = 0
heartbeat_period = math.floor(30/PUSH_INTERVAL)
while True:
if loops % heartbeat_period == 0:
self.logger.info("heartbeat")
loops = 0
try: self.handle_message()
except Exception, e:
self.logger.error('Pypo Recorder Exception: %s', e)
time.sleep(PUSH_INTERVAL)
loops += 1
except Exception,e :
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)

View File

@ -1,26 +0,0 @@
#!/bin/bash
virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
. ${virtualenv_bin}activate
recorder_user="pypo"
# Location of pypo_cli.py Python script
recorder_path="/usr/lib/airtime/show-recorder/"
recorder_script="recorder.py"
api_client_path="/usr/lib/airtime/"
cd ${recorder_path}
exec 2>&1
export HOME="/var/tmp/airtime/show-recorder/"
export TERM=xterm
export PYTHONPATH=${api_client_path}
#this line works: su ${recorder_user} -c "python -u ${recorder_path}${recorder_script}"
# Note the -u when calling python! we need it to get unbuffered binary stdout and stderr
exec python -u ${recorder_path}${recorder_script} > /var/log/airtime/show-recorder/py-interpreter.log 2>&1
# EOF

View File

@ -1,71 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: airtime-show-recorder
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Manage airtime-show-recorder daemon
### END INIT INFO
USERID=pypo
GROUPID=pypo
NAME=Airtime\ Show\ Recorder
DAEMON=/usr/lib/airtime/show-recorder/airtime-show-recorder
PIDFILE=/var/run/airtime-show-recorder.pid
start () {
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID --make-pidfile --pidfile $PIDFILE --startas $DAEMON
monit monitor airtime-show-recorder >/dev/null 2>&1
}
stop () {
# Send TERM after 5 seconds, wait at most 30 seconds.
monit unmonitor airtime-show-recorder >/dev/null 2>&1
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE
rm -f $PIDFILE
}
start_no_monit() {
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID --make-pidfile --pidfile $PIDFILE --startas $DAEMON
}
case "${1:-''}" in
'start')
# start commands here
echo -n "Starting $NAME: "
start
echo "Done."
;;
'stop')
# stop commands here
echo -n "Stopping $NAME: "
stop
echo "Done."
;;
'restart')
# restart commands here
echo -n "Restarting $NAME: "
stop
start
echo "Done."
;;
'start-no-monit')
# restart commands here
echo -n "Starting $NAME: "
start_no_monit
echo "Done."
;;
'status')
# status commands here
/usr/bin/airtime-check-system
;;
*) # no parameter specified
echo "Usage: $SELF start|stop|restart|status"
exit 1
;;
esac

View File

@ -1,74 +0,0 @@
import os
import shutil
import sys
from configobj import ConfigObj
if os.geteuid() != 0:
print "Please run this as root."
sys.exit(1)
def get_current_script_dir():
current_script_dir = os.path.realpath(__file__)
index = current_script_dir.rindex('/')
return current_script_dir[0:index]
def copy_dir(src_dir, dest_dir):
if (os.path.exists(dest_dir)) and (dest_dir != "/"):
shutil.rmtree(dest_dir)
if not (os.path.exists(dest_dir)):
#print "Copying directory "+os.path.realpath(src_dir)+" to "+os.path.realpath(dest_dir)
shutil.copytree(src_dir, dest_dir)
def create_dir(path):
try:
os.makedirs(path)
except Exception, e:
pass
PATH_INI_FILE = '/etc/airtime/recorder.cfg'
try:
# Absolute path this script is in
current_script_dir = get_current_script_dir()
if not os.path.exists(PATH_INI_FILE):
shutil.copy('%s/../recorder.cfg'%current_script_dir, PATH_INI_FILE)
# load config file
try:
config = ConfigObj(PATH_INI_FILE)
except Exception, e:
print 'Error loading config file: ', e
sys.exit(1)
#copy monit files
shutil.copy('%s/../../monit/monit-airtime-generic.cfg'%current_script_dir, '/etc/monit/conf.d/')
if os.environ["disable_auto_start_services"] == "f":
shutil.copy('%s/../monit-airtime-show-recorder.cfg'%current_script_dir, '/etc/monit/conf.d/')
#create temporary media-storage directory
#print "Creating temporary media storage directory"
create_dir(config["base_recorded_files"])
#os.system("chmod -R 755 "+config["base_recorded_files"])
os.system("chown -R pypo:pypo "+config["base_recorded_files"])
#create log directories
#print "Creating log directories"
create_dir(config["log_dir"])
os.system("chmod -R 755 " + config["log_dir"])
os.system("chown -R pypo:pypo "+config["log_dir"])
#copy python files
copy_dir("%s/.."%current_script_dir, config["bin_dir"])
#set python file permissions
#print "Setting permissions"
os.system("chmod -R 755 "+config["bin_dir"])
os.system("chown -R pypo:pypo "+config["bin_dir"])
#copy init.d script
shutil.copy(config["bin_dir"]+"/airtime-show-recorder-init-d", "/etc/init.d/airtime-show-recorder")
except Exception, e:
print e

View File

@ -1,24 +0,0 @@
from subprocess import Popen
import os
import sys
if os.geteuid() != 0:
print "Please run this as root."
sys.exit(1)
try:
if os.environ["disable_auto_start_services"] == "f":
#register init.d script
p = Popen("update-rc.d airtime-show-recorder defaults >/dev/null 2>&1", shell=True)
sts = os.waitpid(p.pid, 0)[1]
#start daemon
print "* Waiting for show-recorder processes to start..."
"""
p = Popen("/etc/init.d/airtime-show-recorder stop", shell=True)
sts = os.waitpid(p.pid, 0)[1]
"""
p = Popen("/etc/init.d/airtime-show-recorder start-no-monit", shell=True)
sts = os.waitpid(p.pid, 0)[1]
except Exception, e:
print e

View File

@ -1,48 +0,0 @@
import os
import shutil
import sys
from configobj import ConfigObj
if os.geteuid() != 0:
print "Please run this as root."
sys.exit(1)
def remove_file(path):
try:
os.remove(path)
except Exception, e:
pass
PATH_INI_FILE = '/etc/airtime/recorder.cfg'
# load config file
try:
config = ConfigObj(PATH_INI_FILE)
except Exception, e:
print 'Error loading config file: ', e
sys.exit(1)
try:
#remove init.d script
print " * Removing Show-Recorder init.d Script"
remove_file('/etc/init.d/airtime-show-recorder')
#remove bin dir
print " * Removing Show-Recorder Program Directory"
shutil.rmtree(config["bin_dir"], ignore_errors=True)
#remove log dir
print " * Removing Show-Recorder Log Directory"
shutil.rmtree(config["log_dir"], ignore_errors=True)
#remove temporary media-storage dir
print " * Removing Show-Recorder Temporary Directory"
shutil.rmtree(config["base_recorded_files"], ignore_errors=True)
#remove monit files
print " * Removing Show-Recorder Monit Files"
remove_file("/etc/monit/conf.d/monit-airtime-show-recorder.cfg")
remove_file("/etc/monit/conf.d/monit-airtime-generic.cfg")
except Exception, e:
print "Error %s" % e

View File

@ -1,19 +0,0 @@
from subprocess import Popen
import os
import sys
if os.geteuid() != 0:
print "Please run this as root."
sys.exit(1)
try:
print "Waiting for show-recorder processes to stop...",
if (os.path.exists('/etc/init.d/airtime-show-recorder')):
p = Popen("/etc/init.d/airtime-show-recorder stop", shell=True)
sts = os.waitpid(p.pid, 0)[1]
print "OK"
else:
print "Wasn't running"
except Exception, e:
print e

View File

@ -1,54 +0,0 @@
# -*- coding: utf-8 -*-
import os
import sys
from configobj import ConfigObj
if os.geteuid() != 0:
print "Please run this as root."
sys.exit(1)
PATH_INI_FILE = '/etc/airtime/recorder.cfg'
def remove_path(path):
os.system('rm -rf "%s"' % path)
def get_current_script_dir():
current_script_dir = os.path.realpath(__file__)
index = current_script_dir.rindex('/')
return current_script_dir[0:index]
def remove_monit_file():
os.system("rm -f /etc/monit/conf.d/monit-airtime-show-recorder.cfg")
try:
# load config file
try:
config = ConfigObj(PATH_INI_FILE)
except Exception, e:
print 'Error loading config file: ', e
sys.exit(1)
os.system("/etc/init.d/airtime-show-recorder stop")
os.system("rm -f /etc/init.d/airtime-show-recorder")
os.system("update-rc.d -f airtime-show-recorder remove >/dev/null 2>&1")
print "Removing monit file"
remove_monit_file()
print "Removing log directories"
remove_path(config["log_dir"])
print "Removing symlinks"
os.system("rm -f /usr/bin/airtime-show-recorder")
print "Removing application files"
remove_path(config["bin_dir"])
print "Removing media files"
remove_path(config["base_recorded_files"])
print "Uninstall complete."
except Exception, e:
print "exception:" + str(e)

View File

@ -1,22 +0,0 @@
[loggers]
keys=root
[handlers]
keys=fileOutHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=fileOutHandler
[handler_fileOutHandler]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=("/var/log/airtime/show-recorder/show-recorder.log", 'a', 1000000, 5,)
[formatter_simpleFormatter]
format=%(asctime)s %(levelname)s - [%(filename)s : %(funcName)s() : line %(lineno)d] - %(message)s
datefmt=

View File

@ -1,9 +0,0 @@
set daemon 10 # Poll at 5 second intervals
set logfile /var/log/monit.log
set httpd port 2812
check process airtime-show-recorder
with pidfile "/var/run/airtime-show-recorder.pid"
start program = "/etc/init.d/airtime-show-recorder start" with timeout 10 seconds
stop program = "/etc/init.d/airtime-show-recorder stop"

View File

@ -1,31 +0,0 @@
api_client = "airtime"
# where the binary files live
bin_dir = '/usr/lib/airtime/show-recorder'
# base path to store recordered shows at
base_recorded_files = '/var/tmp/airtime/show-recorder/'
# where the logging files live
log_dir = '/var/log/airtime/show-recorder'
############################################
# RabbitMQ settings #
############################################
rabbitmq_host = 'localhost'
rabbitmq_user = 'guest'
rabbitmq_password = 'guest'
rabbitmq_vhost = '/'
############################################
# Recorded Audio settings #
############################################
record_bitrate = 256
record_samplerate = 44100
record_channels = 2
record_sample_size = 16
record_timeout = 3600
#can be either ogg|mp3, mp3 recording requires installation of the package "lame"
record_file_type = 'ogg'

View File

@ -1,348 +0,0 @@
import urllib
import logging
import logging.config
import json
import time
import datetime
import os
import sys
import shutil
import socket
import pytz
import signal
from configobj import ConfigObj
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
from subprocess import Popen
from threading import Thread
import mutagen
from api_clients import api_client
# For RabbitMQ
from kombu.connection import BrokerConnection
from kombu.messaging import Exchange, Queue, Consumer, Producer
# configure logging
try:
logging.config.fileConfig("logging.cfg")
except Exception, e:
print 'Error configuring logging: ', e
sys.exit()
# loading config file
try:
config = ConfigObj('/etc/airtime/recorder.cfg')
except Exception, e:
logger = logging.getLogger()
logger.error('Error loading config file: %s', e)
sys.exit()
def getDateTimeObj(time):
timeinfo = time.split(" ")
date = timeinfo[0].split("-")
time = timeinfo[1].split(":")
date = map(int, date)
time = map(int, time)
return datetime.datetime(date[0], date[1], date[2], time[0], time[1], time[2], 0, None)
class ShowRecorder(Thread):
def __init__ (self, show_instance, show_name, filelength, start_time):
Thread.__init__(self)
self.api_client = api_client.api_client_factory(config)
self.filelength = filelength
self.start_time = start_time
self.show_instance = show_instance
self.show_name = show_name
self.logger = logging.getLogger('root')
self.p = None
def record_show(self):
length = str(self.filelength)+".0"
filename = self.start_time
filename = filename.replace(" ", "-")
if config["record_file_type"] in ["mp3", "ogg"]:
filetype = config["record_file_type"]
else:
filetype = "ogg";
filepath = "%s%s.%s" % (config["base_recorded_files"], filename, filetype)
br = config["record_bitrate"]
sr = config["record_samplerate"]
c = config["record_channels"]
ss = config["record_sample_size"]
#-f:16,2,44100
#-b:256
command = "ecasound -f:%s,%s,%s -i alsa -o %s,%s000 -t:%s" % (ss, c, sr, filepath, br, length)
args = command.split(" ")
self.logger.info("starting record")
self.logger.info("command " + command)
self.p = Popen(args)
#blocks at the following line until the child process
#quits
code = self.p.wait()
self.logger.info("finishing record, return code %s", self.p.returncode)
code = self.p.returncode
self.p = None
return code, filepath
def cancel_recording(self):
#add 3 second delay before actually cancelling the show. The reason
#for this is because it appears that ecasound starts 1 second later than
#it should, and therefore this method is sometimes incorrectly called 1
#second before the show ends.
#time.sleep(3)
#send signal interrupt (2)
self.logger.info("Show manually cancelled!")
if (self.p is not None):
self.p.send_signal(signal.SIGINT)
#if self.p is defined, then the child process ecasound is recording
def is_recording(self):
return (self.p is not None)
def upload_file(self, filepath):
filename = os.path.split(filepath)[1]
# Register the streaming http handlers with urllib2
register_openers()
# headers contains the necessary Content-Type and Content-Length
# datagen is a generator object that yields the encoded parameters
datagen, headers = multipart_encode({"file": open(filepath, "rb"), 'name': filename, 'show_instance': self.show_instance})
self.api_client.upload_recorded_show(datagen, headers)
def set_metadata_and_save(self, filepath):
try:
date = self.start_time
md = date.split(" ")
time = md[1].replace(":", "-")
self.logger.info("time: %s" % time)
name = time+"-"+self.show_name
artist = api_client.encode_to("Airtime Show Recorder",'utf-8')
#set some metadata for our file daemon
recorded_file = mutagen.File(filepath, easy=True)
recorded_file['title'] = name
recorded_file['artist'] = artist
recorded_file['date'] = md[0]
recorded_file['tracknumber'] = self.show_instance
recorded_file.save()
except Exception, e:
self.logger.error("Exception: %s", e)
def run(self):
code, filepath = self.record_show()
if code == 0:
try:
self.logger.info("Preparing to upload %s" % filepath)
self.set_metadata_and_save(filepath)
self.upload_file(filepath)
os.remove(filepath)
except Exception, e:
self.logger.error(e)
else:
self.logger.info("problem recording show")
os.remove(filepath)
class CommandListener():
def __init__(self):
#Thread.__init__(self)
self.api_client = api_client.api_client_factory(config)
self.api_client.register_component("show-recorder")
self.logger = logging.getLogger('root')
self.sr = None
self.current_schedule = {}
self.shows_to_record = {}
self.time_till_next_show = config["record_timeout"]
self.logger.info("RecorderFetch: init complete")
self.server_timezone = '';
def init_rabbit_mq(self):
self.logger.info("Initializing RabbitMQ stuff")
try:
schedule_exchange = Exchange("airtime-show-recorder", "direct", durable=True, auto_delete=True)
schedule_queue = Queue("recorder-fetch", exchange=schedule_exchange, key="foo")
self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], config["rabbitmq_vhost"])
channel = self.connection.channel()
consumer = Consumer(channel, schedule_queue)
consumer.register_callback(self.handle_message)
consumer.consume()
except Exception, e:
self.logger.error(e)
return False
return True
def handle_message(self, body, message):
# ACK the message to take it off the queue
message.ack()
self.logger.info("Received command from RabbitMQ: " + message.body)
m = json.loads(message.body)
command = m['event_type']
self.logger.info("Handling command: " + command)
if(command == 'update_schedule'):
temp = m['shows']
if temp is not None:
self.parse_shows(temp)
self.server_timezone = m['server_timezone']
elif(command == 'cancel_recording'):
if self.sr is not None and self.sr.is_recording():
self.sr.cancel_recording()
def parse_shows(self, shows):
self.logger.info("Parsing show schedules...")
self.shows_to_record = {}
for show in shows:
show_starts = getDateTimeObj(show[u'starts'])
show_end = getDateTimeObj(show[u'ends'])
time_delta = show_end - show_starts
self.shows_to_record[show[u'starts']] = [time_delta, show[u'instance_id'], show[u'name']]
delta = self.get_time_till_next_show()
# awake at least 5 seconds prior to the show start
self.time_till_next_show = delta - 5
self.logger.info(self.shows_to_record)
def get_time_till_next_show(self):
if len(self.shows_to_record) != 0:
tnow = datetime.datetime.utcnow()
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
next_show = getDateTimeObj(start_time)
delta = next_show - tnow
out = delta.seconds
self.logger.debug("Next show %s", next_show)
self.logger.debug("Now %s", tnow)
else:
out = config["record_timeout"]
return out
def start_record(self):
if len(self.shows_to_record) != 0:
try:
delta = self.get_time_till_next_show()
self.logger.debug("sleeping %s seconds until show", delta)
time.sleep(delta)
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
show_length = self.shows_to_record[start_time][0]
show_instance = self.shows_to_record[start_time][1]
show_name = self.shows_to_record[start_time][2]
T = pytz.timezone(self.server_timezone)
start_time_on_UTC = getDateTimeObj(start_time)
start_time_on_server = start_time_on_UTC.replace(tzinfo=pytz.utc).astimezone(T)
start_time_formatted = '%(year)d-%(month)02d-%(day)02d %(hour)02d:%(min)02d:%(sec)02d' % \
{'year': start_time_on_server.year, 'month': start_time_on_server.month, 'day': start_time_on_server.day,\
'hour': start_time_on_server.hour, 'min': start_time_on_server.minute, 'sec': start_time_on_server.second}
self.sr = ShowRecorder(show_instance, show_name, show_length.seconds, start_time_formatted)
self.sr.start()
#remove show from shows to record.
del self.shows_to_record[start_time]
self.time_till_next_show = self.get_time_till_next_show()
except Exception,e :
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
else:
self.logger.debug("No recording scheduled...")
"""
Main loop of the thread:
Wait for schedule updates from RabbitMQ, but in case there arent any,
poll the server to get the upcoming schedule.
"""
def run(self):
self.logger.info("Started...")
while not self.init_rabbit_mq():
self.logger.error("Error connecting to RabbitMQ Server. Trying again in few seconds")
time.sleep(5)
# Bootstrap: since we are just starting up, we need to grab the
# most recent schedule. After that we can just wait for updates.
try:
temp = self.api_client.get_shows_to_record()
if temp is not None:
shows = temp['shows']
self.server_timezone = temp['server_timezone']
self.parse_shows(shows)
self.logger.info("Bootstrap complete: got initial copy of the schedule")
except Exception, e:
self.logger.error(e)
loops = 1
recording = False
while True:
self.logger.info("Loop #%s", loops)
try:
# block until 5 seconds before the next show start
self.connection.drain_events(timeout=int(self.time_till_next_show))
except socket.timeout, s:
self.logger.info(s)
# start_record set time_till_next_show to config["record_timeout"] so we should check before
# if timeout amount was 1 hr..
update_schedule = False
if int(self.time_till_next_show) == int(config["record_timeout"]) :
update_schedule = True
# start recording
self.start_record()
# if real timeout happended get show schedule from airtime
if update_schedule :
temp = self.api_client.get_shows_to_record()
if temp is not None:
shows = temp['shows']
self.server_timezone = temp['server_timezone']
self.parse_shows(shows)
self.logger.info("Real Timeout: the schedule has updated")
except Exception, e:
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
time.sleep(3)
loops += 1
if __name__ == '__main__':
cl = CommandListener()
cl.run()

View File

@ -189,17 +189,6 @@ class AirtimeCheck {
self::output_status("MEDIA_MONITOR_MEM_PERC", "0%");
self::output_status("MEDIA_MONITOR_CPU_PERC", "0%");
}
if (isset($services->show_recorder)) {
self::output_status("SHOW_RECORDER_PROCESS_ID", $data->services->show_recorder->process_id);
self::output_status("SHOW_RECORDER_RUNNING_SECONDS", $data->services->show_recorder->uptime_seconds);
self::output_status("SHOW_RECORDER_MEM_PERC", $data->services->show_recorder->memory_perc);
self::output_status("SHOW_RECORDER_CPU_PERC", $data->services->show_recorder->cpu_perc);
} else {
self::output_status("SHOW_RECORDER_PROCESS_ID", "FAILED");
self::output_status("SHOW_RECORDER_RUNNING_SECONDS", "0");
self::output_status("SHOW_RECORDER_MEM_PERC", "0%");
self::output_status("SHOW_RECORDER_CPU_PERC", "0%");
}
if (isset($services->rabbitmq)) {
self::output_status("RABBITMQ_PROCESS_ID", $data->services->rabbitmq->process_id);
self::output_status("RABBITMQ_RUNNING_SECONDS", $data->services->rabbitmq->uptime_seconds);