Merge branch '2.3.x' of dev.sourcefabric.org:airtime into 2.3.x
This commit is contained in:
commit
d63865625d
|
@ -273,7 +273,8 @@ class PreferenceController extends Zend_Controller_Action
|
|||
Application_Model_Preference::SetEnableReplayGain($values["enableReplayGain"]);
|
||||
Application_Model_Preference::setReplayGainModifier($values["replayGainModifier"]);
|
||||
$md = array('schedule' => Application_Model_Schedule::getSchedule());
|
||||
Application_Model_RabbitMq::PushSchedule();
|
||||
Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md);
|
||||
//Application_Model_RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
if (!Application_Model_Preference::GetMasterDjConnectionUrlOverride()) {
|
||||
|
|
|
@ -32,6 +32,8 @@ class Logging {
|
|||
{
|
||||
if (is_array($p_msg) || is_object($p_msg)) {
|
||||
return print_r($p_msg, true);
|
||||
} else if (is_bool($p_msg)) {
|
||||
return $p_msg ? "true" : "false";
|
||||
} else {
|
||||
return $p_msg;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
2.3.0 - Jan 21st, 2013
|
||||
* New features
|
||||
* Localization (Brazilian, Chinese, Czech, English, French, German, Italian, Korean, Portugese, Russian, Spanish)
|
||||
* Localization (Chinese, Czech, English, French, German, Italian, Korean,
|
||||
Portuguese, Russian, Spanish)
|
||||
* User management page for non-admin users
|
||||
* Listener statistics (Icecast/Shoutcast)
|
||||
* Airtime no longer requires Apache document root
|
||||
|
|
|
@ -15,6 +15,8 @@ INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_admin_pas
|
|||
UPDATE cc_music_dirs SET directory = directory || '/' where id in (select id from cc_music_dirs where substr(directory, length(directory)) != '/');
|
||||
UPDATE cc_files SET filepath = substring(filepath from 2) where id in (select id from cc_files where substring(filepath from 1 for 1) = '/');
|
||||
|
||||
UPDATE cc_files SET cueout = length where cueout = '00:00:00';
|
||||
|
||||
INSERT INTO cc_pref("keystr", "valstr") VALUES('locale', 'en_CA');
|
||||
|
||||
INSERT INTO cc_pref("subjid", "keystr", "valstr") VALUES(1, 'user_locale', 'en_CA');
|
||||
|
|
|
@ -80,23 +80,19 @@ class ApiRequest(object):
|
|||
if logger is None: self.logger = logging
|
||||
else: self.logger = logger
|
||||
def __call__(self,_post_data=None, **kwargs):
|
||||
# TODO : get rid of god damn urllib and replace everything with
|
||||
# grequests or requests at least
|
||||
final_url = self.url.params(**kwargs).url()
|
||||
if _post_data is not None: _post_data = urllib.urlencode(_post_data)
|
||||
try:
|
||||
req = urllib2.Request(final_url, _post_data)
|
||||
response = urllib2.urlopen(req).read()
|
||||
except Exception, e:
|
||||
self.logger.error('Exception: %s', e)
|
||||
import traceback
|
||||
top = traceback.format_exc()
|
||||
self.logger.error("traceback: %s", top)
|
||||
response = ""
|
||||
self.logger.error('Exception: %s', e)
|
||||
self.logger.error("traceback: %s", traceback.format_exc())
|
||||
raise
|
||||
# Ghetto hack for now because we don't the content type we are getting
|
||||
# (Pointless to look at mime since it's not being set correctly always)
|
||||
try: return json.loads(response)
|
||||
except ValueError: return response
|
||||
return json.loads(response)
|
||||
|
||||
def req(self, *args, **kwargs):
|
||||
self.__req = lambda : self(*args, **kwargs)
|
||||
|
@ -182,13 +178,20 @@ class AirtimeApiClient(object):
|
|||
except: return (False, None)
|
||||
|
||||
def notify_liquidsoap_started(self):
|
||||
return self.services.notify_liquidsoap_started()
|
||||
try:
|
||||
self.services.notify_liquidsoap_started()
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
|
||||
def notify_media_item_start_playing(self, media_id):
|
||||
""" This is a callback from liquidsoap, we use this to notify
|
||||
about the currently playing *song*. We get passed a JSON string
|
||||
which we handed to liquidsoap in get_liquidsoap_data(). """
|
||||
return self.services.update_start_playing_url(media_id=media_id)
|
||||
try:
|
||||
return self.services.update_start_playing_url(media_id=media_id)
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
return None
|
||||
|
||||
# TODO : get this routine out of here it doesn't belong at all here
|
||||
def get_liquidsoap_data(self, pkey, schedule):
|
||||
|
@ -199,7 +202,11 @@ class AirtimeApiClient(object):
|
|||
return data
|
||||
|
||||
def get_shows_to_record(self):
|
||||
return self.services.show_schedule_url()
|
||||
try:
|
||||
return self.services.show_schedule_url()
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
return None
|
||||
|
||||
def upload_recorded_show(self, data, headers):
|
||||
logger = self.logger
|
||||
|
@ -235,8 +242,12 @@ class AirtimeApiClient(object):
|
|||
return response
|
||||
|
||||
def check_live_stream_auth(self, username, password, dj_type):
|
||||
return self.services.check_live_stream_auth(
|
||||
username=username, password=password, djtype=dj_type)
|
||||
try:
|
||||
return self.services.check_live_stream_auth(
|
||||
username=username, password=password, djtype=dj_type)
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
return {}
|
||||
|
||||
def construct_url(self,config_action_key):
|
||||
"""Constructs the base url for every request"""
|
||||
|
@ -249,7 +260,11 @@ class AirtimeApiClient(object):
|
|||
return url
|
||||
|
||||
def setup_media_monitor(self):
|
||||
return self.services.media_setup_url()
|
||||
try:
|
||||
return self.services.media_setup_url()
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.info(str(e))
|
||||
|
||||
def send_media_monitor_requests(self, action_list, dry=False):
|
||||
"""
|
||||
|
@ -310,13 +325,25 @@ class AirtimeApiClient(object):
|
|||
return []
|
||||
|
||||
def list_all_watched_dirs(self):
|
||||
return self.services.list_all_watched_dirs()
|
||||
try:
|
||||
return self.services.list_all_watched_dirs()
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def add_watched_dir(self, path):
|
||||
return self.services.add_watched_dir(path=base64.b64encode(path))
|
||||
try:
|
||||
return self.services.add_watched_dir(path=base64.b64encode(path))
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def remove_watched_dir(self, path):
|
||||
return self.services.remove_watched_dir(path=base64.b64encode(path))
|
||||
try:
|
||||
return self.services.remove_watched_dir(path=base64.b64encode(path))
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def set_storage_dir(self, path):
|
||||
return self.services.set_storage_dir(path=base64.b64encode(path))
|
||||
|
@ -334,7 +361,11 @@ class AirtimeApiClient(object):
|
|||
(component = media-monitor, pypo etc.) ip address, and later use it
|
||||
to query monit via monit's http service, or download log files via a
|
||||
http server. """
|
||||
return self.services.register_component(component=component)
|
||||
try:
|
||||
return self.services.register_component(component=component)
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def notify_liquidsoap_status(self, msg, stream_id, time):
|
||||
logger = self.logger
|
||||
|
@ -343,6 +374,7 @@ class AirtimeApiClient(object):
|
|||
self.services.update_liquidsoap_status.req(msg=encoded_msg, stream_id=stream_id,
|
||||
boot_time=time).retry(5)
|
||||
except Exception, e:
|
||||
#TODO
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
def notify_source_status(self, sourcename, status):
|
||||
|
@ -351,11 +383,16 @@ class AirtimeApiClient(object):
|
|||
return self.services.update_source_status.req(sourcename=sourcename,
|
||||
status=status).retry(5)
|
||||
except Exception, e:
|
||||
#TODO
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
def get_bootstrap_info(self):
|
||||
""" Retrive infomations needed on bootstrap time """
|
||||
return self.services.get_bootstrap_info()
|
||||
""" Retrieve infomations needed on bootstrap time """
|
||||
try:
|
||||
return self.services.get_bootstrap_info()
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def get_files_without_replay_gain_value(self, dir_id):
|
||||
"""
|
||||
|
@ -364,7 +401,11 @@ class AirtimeApiClient(object):
|
|||
to this file is the return value.
|
||||
"""
|
||||
#http://localhost/api/get-files-without-replay-gain/dir_id/1
|
||||
return self.services.get_files_without_replay_gain(dir_id=dir_id)
|
||||
try:
|
||||
return self.services.get_files_without_replay_gain(dir_id=dir_id)
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def get_files_without_silan_value(self):
|
||||
"""
|
||||
|
@ -372,22 +413,35 @@ class AirtimeApiClient(object):
|
|||
calculated. This list of files is downloaded into a file and the path
|
||||
to this file is the return value.
|
||||
"""
|
||||
return self.services.get_files_without_silan_value()
|
||||
try:
|
||||
return self.services.get_files_without_silan_value()
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def update_replay_gain_values(self, pairs):
|
||||
"""
|
||||
'pairs' is a list of pairs in (x, y), where x is the file's database
|
||||
row id and y is the file's replay_gain value in dB
|
||||
"""
|
||||
self.logger.debug(self.services.update_replay_gain_value(
|
||||
_post_data={'data': json.dumps(pairs)}))
|
||||
try:
|
||||
self.logger.debug(self.services.update_replay_gain_value(
|
||||
_post_data={'data': json.dumps(pairs)}))
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
|
||||
def update_cue_values_by_silan(self, pairs):
|
||||
"""
|
||||
'pairs' is a list of pairs in (x, y), where x is the file's database
|
||||
row id and y is the file's cue values in dB
|
||||
"""
|
||||
print self.services.update_cue_values_by_silan(_post_data={'data': json.dumps(pairs)})
|
||||
try:
|
||||
print self.services.update_cue_values_by_silan(_post_data={'data': json.dumps(pairs)})
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
|
||||
def notify_webstream_data(self, data, media_id):
|
||||
|
@ -395,19 +449,35 @@ class AirtimeApiClient(object):
|
|||
Update the server with the latest metadata we've received from the
|
||||
external webstream
|
||||
"""
|
||||
self.logger.info( self.services.notify_webstream_data.req(
|
||||
_post_data={'data':data}, media_id=str(media_id)).retry(5))
|
||||
try:
|
||||
self.logger.info( self.services.notify_webstream_data.req(
|
||||
_post_data={'data':data}, media_id=str(media_id)).retry(5))
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def get_stream_parameters(self):
|
||||
response = self.services.get_stream_parameters()
|
||||
self.logger.debug(response)
|
||||
return response
|
||||
try:
|
||||
response = self.services.get_stream_parameters()
|
||||
self.logger.debug(response)
|
||||
return response
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def push_stream_stats(self, data):
|
||||
# TODO : users of this method should do their own error handling
|
||||
response = self.services.push_stream_stats(_post_data={'data': json.dumps(data)})
|
||||
return response
|
||||
try:
|
||||
response = self.services.push_stream_stats(_post_data={'data': json.dumps(data)})
|
||||
return response
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
||||
def update_stream_setting_table(self, data):
|
||||
response = self.services.update_stream_setting_table(_post_data={'data': json.dumps(data)})
|
||||
return response
|
||||
try:
|
||||
response = self.services.update_stream_setting_table(_post_data={'data': json.dumps(data)})
|
||||
return response
|
||||
except Exception, e:
|
||||
#TODO
|
||||
self.logger.error(str(e))
|
||||
|
|
|
@ -15,4 +15,7 @@ elif dj_type == '--dj':
|
|||
|
||||
response = api_clients.check_live_stream_auth(username, password, source_type)
|
||||
|
||||
print response['msg']
|
||||
if 'msg' in response:
|
||||
print response['msg']
|
||||
else:
|
||||
print False
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
|
||||
check process airtime-playout
|
||||
with pidfile "/var/run/airtime-playout.pid"
|
||||
start program = "/etc/init.d/airtime-playout monit-restart" with timeout 5 seconds
|
||||
start program = "/etc/init.d/airtime-playout start" with timeout 5 seconds
|
||||
stop program = "/etc/init.d/airtime-playout stop"
|
||||
|
|
|
@ -176,7 +176,7 @@ if __name__ == '__main__':
|
|||
sys.exit()
|
||||
|
||||
api_client = api_client.AirtimeApiClient()
|
||||
|
||||
|
||||
ReplayGainUpdater.start_reply_gain(api_client)
|
||||
|
||||
api_client.register_component("pypo")
|
||||
|
|
|
@ -18,7 +18,8 @@ from std_err_override import LogWriter
|
|||
from configobj import ConfigObj
|
||||
|
||||
# configure logging
|
||||
logging.config.fileConfig("logging.cfg")
|
||||
logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
|
||||
logging.config.fileConfig(logging_cfg)
|
||||
logger = logging.getLogger()
|
||||
LogWriter.override_std_err(logger)
|
||||
|
||||
|
@ -135,7 +136,7 @@ class PypoFetch(Thread):
|
|||
try:
|
||||
lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
self.logger.info(command)
|
||||
logger.info(command)
|
||||
tn.write(command)
|
||||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
|
|
|
@ -9,6 +9,7 @@ import logging.config
|
|||
import telnetlib
|
||||
import calendar
|
||||
import math
|
||||
import os
|
||||
from pypofetch import PypoFetch
|
||||
|
||||
from Queue import Empty
|
||||
|
@ -21,7 +22,8 @@ from configobj import ConfigObj
|
|||
|
||||
|
||||
# configure logging
|
||||
logging.config.fileConfig("logging.cfg")
|
||||
logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
|
||||
logging.config.fileConfig(logging_cfg)
|
||||
logger = logging.getLogger()
|
||||
LogWriter.override_std_err(logger)
|
||||
|
||||
|
@ -249,7 +251,7 @@ class PypoPush(Thread):
|
|||
self.start_web_stream_buffer(current_item)
|
||||
self.start_web_stream(current_item)
|
||||
if is_file(current_item):
|
||||
self.modify_cue_point(file_chain[0])
|
||||
file_chain = self.modify_first_link_cue_point(file_chain)
|
||||
self.push_to_liquidsoap(file_chain)
|
||||
#we've changed the queue, so let's refetch it
|
||||
liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap()
|
||||
|
@ -279,7 +281,7 @@ class PypoPush(Thread):
|
|||
|
||||
chain_to_push = file_chain[problem_at_iteration:]
|
||||
if len(chain_to_push) > 0:
|
||||
self.modify_cue_point(chain_to_push[0])
|
||||
chain_to_push = self.modify_first_link_cue_point(chain_to_push)
|
||||
self.push_to_liquidsoap(chain_to_push)
|
||||
|
||||
|
||||
|
@ -363,6 +365,18 @@ class PypoPush(Thread):
|
|||
original_cue_in_td = timedelta(seconds=float(link['cue_in']))
|
||||
link['cue_in'] = self.date_interval_to_seconds(original_cue_in_td) + diff_sec
|
||||
|
||||
def modify_first_link_cue_point(self, chain):
|
||||
if not len(chain):
|
||||
return []
|
||||
|
||||
first_link = chain[0]
|
||||
|
||||
self.modify_cue_point(first_link)
|
||||
if float(first_link['cue_in']) >= float(first_link['cue_out']):
|
||||
chain = chain [1:]
|
||||
|
||||
return chain
|
||||
|
||||
"""
|
||||
Returns two chains, original chain and current_chain. current_chain is a subset of
|
||||
original_chain but can also be equal to original chain.
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
which py.test
|
||||
pytest_exist=$?
|
||||
|
||||
if [ "$pytest_exist" != "0" ]; then
|
||||
echo "Need to have py.test installed. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT=`readlink -f $0`
|
||||
# Absolute directory this script is in
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
export PYTHONPATH=$PYTHONPATH:$SCRIPTPATH/..:$SCRIPTPATH/../..
|
||||
|
||||
py.test
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
from pypopush import PypoPush
|
||||
from threading import Lock
|
||||
from Queue import Queue
|
||||
|
||||
import datetime
|
||||
|
||||
pypoPush_q = Queue()
|
||||
telnet_lock = Lock()
|
||||
|
||||
pp = PypoPush(pypoPush_q, telnet_lock)
|
||||
|
||||
def test_modify_cue_in():
|
||||
link = pp.modify_first_link_cue_point([])
|
||||
assert len(link) == 0
|
||||
|
||||
min_ago = datetime.datetime.utcnow() - datetime.timedelta(minutes = 1)
|
||||
link = [{"start":min_ago.strftime("%Y-%m-%d-%H-%M-%S"),
|
||||
"cue_in":"0", "cue_out":"30"}]
|
||||
link = pp.modify_first_link_cue_point(link)
|
||||
assert len(link) == 0
|
||||
|
||||
link = [{"start":min_ago.strftime("%Y-%m-%d-%H-%M-%S"),
|
||||
"cue_in":"0", "cue_out":"70"}]
|
||||
link = pp.modify_first_link_cue_point(link)
|
||||
assert len(link) == 1
|
||||
|
|
@ -170,6 +170,8 @@ def WatchAddAction(option, opt, value, parser):
|
|||
print "%s added to watched folder list successfully" % path
|
||||
else:
|
||||
print "Adding a watched folder failed: %s" % res['msg']['error']
|
||||
print "This error most likely caused by wrong permissions"
|
||||
print "Try fixing this error by chmodding the parent directory(ies)"
|
||||
else:
|
||||
print "Given path is not a directory: %s" % path
|
||||
|
||||
|
|
Loading…
Reference in New Issue