Merge branch '2.4.x' into 2.4.x-saas

Conflicts:
	python_apps/pypo/liquidsoap_scripts/ls_script.liq
	utils/phone_home_stat.php
This commit is contained in:
Naomi Aro 2013-06-26 01:25:26 -04:00
commit f2d5fa96da
114 changed files with 9850 additions and 9170 deletions

View file

@ -138,8 +138,8 @@ class ApiRequest(object):
content_type = f.info().getheader('Content-Type')
response = f.read()
except Exception, e:
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", traceback.format_exc())
#self.logger.error('Exception: %s', e)
#self.logger.error("traceback: %s", traceback.format_exc())
raise
try:
@ -149,8 +149,8 @@ class ApiRequest(object):
else:
raise InvalidContentType()
except Exception:
self.logger.error(response)
self.logger.error("traceback: %s", traceback.format_exc())
#self.logger.error(response)
#self.logger.error("traceback: %s", traceback.format_exc())
raise
def req(self, *args, **kwargs):

View file

@ -2,7 +2,7 @@
### BEGIN INIT INFO
# Provides: airtime-media-monitor
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Start: $local_fs $remote_fs $network $syslog $all
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6

View file

@ -1,5 +1,6 @@
import pyinotify
import time
import os
from pydispatch import dispatcher
from os.path import normpath
@ -186,13 +187,12 @@ class Manager(Loggable):
try: mmp.create_dir(path)
except mmp.FailedToCreateDir as e: self.unexpected_exception(e)
os.chmod(store_paths['organize'], 0775)
self.set_problem_files_path(store_paths['problem_files'])
self.set_imported_path(store_paths['imported'])
self.set_recorded_path(store_paths['recorded'])
self.set_organize_path(store_paths['organize'])
mmp.create_dir(store)
for p in store_paths.values():
mmp.create_dir(p)
def has_watch(self, path):
""" returns true if the path is being watched or not. Any kind

View file

@ -2,7 +2,7 @@
### BEGIN INIT INFO
# Provides: airtime-liquidsoap
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Start: $local_fs $remote_fs $network $syslog $all
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
@ -18,7 +18,6 @@ PIDFILE=/var/run/airtime-liquidsoap.pid
EXEC='/usr/bin/airtime-liquidsoap'
start () {
mkdir -p /var/log/airtime/pypo-liquidsoap
chown $USERID:$GROUPID /var/log/airtime/pypo-liquidsoap
@ -36,9 +35,19 @@ start () {
}
stop () {
timeout --version >/dev/null 2>&1
RESULT="$?"
#send term signal after 10 seconds
timeout -s9 10s /usr/lib/airtime/airtime_virtualenv/bin/python \
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
if [ "$RESULT" = "0" ]; then
timeout -s9 10s /usr/lib/airtime/airtime_virtualenv/bin/python \
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
else
#some earlier versions of Ubuntu (Lucid) had a different timeout
#command that takes different input parameters.
timeout 10 /usr/lib/airtime/airtime_virtualenv/bin/python \
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
fi
# Send TERM after 5 seconds, wait at most 30 seconds.
#start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE
start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --exec $EXEC

View file

@ -2,7 +2,7 @@
### BEGIN INIT INFO
# Provides: airtime-playout
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Start: $local_fs $remote_fs $network $syslog $all
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6

View file

@ -88,8 +88,8 @@ try:
if "airtime_service_start" in os.environ and os.environ["airtime_service_start"] == "t":
print "* Waiting for pypo processes to start..."
subprocess.call("invoke-rc.d airtime-playout start > /dev/null 2>&1", shell=True)
subprocess.call("invoke-rc.d airtime-liquidsoap start > /dev/null 2>&1", shell=True)
subprocess.call("invoke-rc.d airtime-playout start > /dev/null 2>&1", shell=True)
except Exception, e:
print e

View file

@ -0,0 +1,24 @@
if bitrate == 24 then
ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 32 then
ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 48 then
ignore(output_stereo(%fdkaac(bitrate = 48, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 64 then
ignore(output_stereo(%fdkaac(bitrate = 64, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 96 then
ignore(output_stereo(%fdkaac(bitrate = 96, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 128 then
ignore(output_stereo(%fdkaac(bitrate = 128, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 160 then
ignore(output_stereo(%fdkaac(bitrate = 160, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 192 then
ignore(output_stereo(%fdkaac(bitrate = 192, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 224 then
ignore(output_stereo(%fdkaac(bitrate = 224, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 256 then
ignore(output_stereo(%fdkaac(bitrate = 256, aot="mpeg4_he_aac_v2"), !source))
elsif bitrate == 320 then
ignore(output_stereo(%fdkaac(bitrate = 320, aot="mpeg4_he_aac_v2"), !source))
end

View file

@ -1,6 +1,7 @@
import logging
import sys
import time
import traceback
from api_clients.api_client import AirtimeApiClient
def generate_liquidsoap_config(ss):
@ -26,19 +27,21 @@ def generate_liquidsoap_config(ss):
fh.close()
logging.basicConfig(format='%(message)s')
ac = AirtimeApiClient(logging.getLogger())
attempts = 0
max_attempts = 5
max_attempts = 10
successful = False
while True:
while not successful:
try:
ac = AirtimeApiClient(logging.getLogger())
ss = ac.get_stream_setting()
generate_liquidsoap_config(ss)
break
successful = True
except Exception, e:
if attempts == max_attempts:
print "Unable to connect to the Airtime server."
logging.error(str(e))
logging.error("traceback: %s", traceback.format_exc())
sys.exit(1)
else:
time.sleep(3)

View file

@ -1,10 +1,15 @@
def notify(m)
#current_media_id := string_of(m['schedule_table_id'])
command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --media-id=#{m['schedule_table_id']} &"
log(command)
system(command)
end
def notify_queue(m)
f = !dynamic_metadata_callback
ignore(f(m))
notify(m)
end
def notify_stream(m)
json_str = string.replace(pattern="\n",(fun (s) -> ""), json_of(m))
#if a string has a single apostrophe in it, let's comment it out by ending the string before right before it
@ -18,12 +23,19 @@ end
# A function applied to each metadata chunk
def append_title(m) =
log("Using stream_format #{!stream_metadata_type}")
if !stream_metadata_type == 1 then
[("title", "#{!show_name} - #{m['artist']} - #{m['title']}")]
elsif !stream_metadata_type == 2 then
[("title", "#{!station_name} - #{!show_name}")]
if list.mem_assoc("mapped", m) then
#protection against applying this function twice. It shouldn't be happening
#and bug file with Liquidsoap.
m
else
[("title", "#{m['artist']} - #{m['title']}")]
if !stream_metadata_type == 1 then
[("title", "#{!show_name} - #{m['artist']} - #{m['title']}"), ("mapped", "true")]
elsif !stream_metadata_type == 2 then
[("title", "#{!station_name} - #{!show_name}"), ("mapped", "true")]
else
[("title", "#{m['artist']} - #{m['title']}"), ("mapped", "true")]
end
end
end
@ -146,6 +158,12 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
%include "aacplus.liq"
end
%endif
%ifencoder %fdkaac
if type == "fdkaac" then
%include "fdkaac.liq"
end
%endif
else
user_ref = ref user
if user == "" then

View file

@ -24,6 +24,8 @@ default_dj_fade = ref 0.
station_name = ref ''
show_name = ref ''
dynamic_metadata_callback = ref fun (s) -> begin () end
s1_connected = ref ''
s2_connected = ref ''
s3_connected = ref ''
@ -47,7 +49,8 @@ def create_source()
# the crossfade function controls fade in/out
l = crossfade_airtime(l)
l = on_metadata(notify, l)
l = on_metadata(notify_queue, l)
sources := list.append([l], !sources)
server.register(namespace="queues",
"s#{!source_id}_skip",
@ -69,12 +72,10 @@ create_source()
create_source()
queue = add(!sources, normalize=false)
pair = insert_metadata(queue)
dynamic_metadata_callback := fst(pair)
queue = snd(pair)
<<<<<<< HEAD
=======
# the crossfade function controls fade in/out
>>>>>>> 551d65ebf04d877bdba009a92c62bfa4f08eea9c
output.dummy(fallible=true, queue)
http = input.http_restart(id="http")

View file

@ -56,8 +56,8 @@ class SilanAnalyzer(Thread):
try: data['cueout'] = str('{0:f}'.format(info['sound'][-1][1]))
except: pass
except Exception, e:
self.logger.error(str(command))
self.logger.error(e)
self.logger.warn(str(command))
self.logger.warn(e)
processed_data.append((f['id'], data))
total += 1
if total % 5 == 0:

View file

@ -4,6 +4,8 @@
set httpd port 2812
check process airtime-liquidsoap matching "airtime-liquidsoap.*airtime.*ls_script"
if does not exist for 3 cycles then restart
start program = "/etc/init.d/airtime-liquidsoap start" with timeout 30 seconds
stop program = "/etc/init.d/airtime-liquidsoap stop"

View file

@ -3,7 +3,6 @@
set httpd port 2812
check process airtime-liquidsoap
with pidfile "/var/run/airtime-liquidsoap.pid"
check process airtime-liquidsoap with pidfile "/var/run/airtime-liquidsoap.pid"
start program = "/etc/init.d/airtime-liquidsoap start" with timeout 5 seconds
stop program = "/etc/init.d/airtime-liquidsoap stop"

View file

@ -25,6 +25,7 @@ from recorder import Recorder
from listenerstat import ListenerStat
from pypomessagehandler import PypoMessageHandler
from pypoliquidsoap import PypoLiquidsoap
from timeout import ls_timeout
from media.update.replaygainupdater import ReplayGainUpdater
from media.update.silananalyzer import SilanAnalyzer
@ -156,6 +157,7 @@ def keyboardInterruptHandler(signum, frame):
logger.info('\nKeyboard Interrupt\n')
sys.exit(0)
@ls_timeout
def liquidsoap_get_info(telnet_lock, host, port, logger):
logger.debug("Checking to see if Liquidsoap is running")
try:

View file

@ -19,6 +19,7 @@ from subprocess import Popen, PIPE
from api_clients import api_client
from std_err_override import LogWriter
from timeout import ls_timeout
# configure logging
@ -38,12 +39,13 @@ signal.signal(signal.SIGINT, keyboardInterruptHandler)
POLL_INTERVAL = 1800
config_static = None
class PypoFetch(Thread):
def __init__(self, pypoFetch_q, pypoPush_q, media_q, telnet_lock, pypo_liquidsoap, config):
Thread.__init__(self)
global config_static
#Hacky...
PypoFetch.ref = self
self.api_client = api_client.AirtimeApiClient()
self.fetch_queue = pypoFetch_q
@ -51,7 +53,6 @@ class PypoFetch(Thread):
self.media_prepare_queue = media_q
self.last_update_schedule_timestamp = time.time()
self.config = config
config_static = config
self.listener_timeout = POLL_INTERVAL
self.telnet_lock = telnet_lock
@ -176,11 +177,19 @@ class PypoFetch(Thread):
commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8'))
self.pypo_liquidsoap.get_telnet_dispatcher().telnet_send(commands)
self.pypo_liquidsoap.clear_all_queues()
self.pypo_liquidsoap.clear_queue_tracker()
def restart_liquidsoap(self):
try:
self.telnet_lock.acquire()
"""do not block - if we receive the lock then good - no other thread
will try communicating with Liquidsoap. If we don't receive, it may
mean some thread blocked and is still holding the lock. Restarting
Liquidsoap will cause that thread to release the lock as an Exception
will be thrown."""
self.telnet_lock.acquire(False)
self.logger.info("Restarting Liquidsoap")
subprocess.call('/etc/init.d/airtime-liquidsoap restart', shell=True)
@ -202,14 +211,6 @@ class PypoFetch(Thread):
finally:
self.telnet_lock.release()
try:
self.set_bootstrap_variables()
#get the most up to date schedule, which will #initiate the process
#of making sure Liquidsoap is playing the schedule
self.persistent_manual_schedule_fetch(max_attempts=5)
except Exception, e:
self.logger.error(str(e))
"""
TODO: This function needs to be way shorter, and refactored :/ - MK
"""
@ -307,6 +308,7 @@ class PypoFetch(Thread):
self.logger.info("No change detected in setting...")
self.update_liquidsoap_connection_status()
@ls_timeout
def update_liquidsoap_connection_status(self):
"""
updates the status of Liquidsoap connection to the streaming server
@ -353,6 +355,7 @@ class PypoFetch(Thread):
self.api_client.notify_liquidsoap_status("OK", stream_id, str(fake_time))
@ls_timeout
def update_liquidsoap_stream_format(self, stream_format):
# Push stream metadata to liquidsoap
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
@ -369,6 +372,7 @@ class PypoFetch(Thread):
finally:
self.telnet_lock.release()
@ls_timeout
def update_liquidsoap_transition_fade(self, fade):
# Push stream metadata to liquidsoap
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
@ -385,6 +389,7 @@ class PypoFetch(Thread):
finally:
self.telnet_lock.release()
@ls_timeout
def update_liquidsoap_station_name(self, station_name):
# Push stream metadata to liquidsoap
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
@ -441,9 +446,11 @@ class PypoFetch(Thread):
media_item['file_ready'] = False
media_filtered[key] = media_item
media_item['start'] = datetime.strptime(media_item['start'], "%Y-%m-%d-%H-%M-%S")
media_item['end'] = datetime.strptime(media_item['end'], "%Y-%m-%d-%H-%M-%S")
media_copy[media_item['start']] = media_item
media_item['start'] = datetime.strptime(media_item['start'],
"%Y-%m-%d-%H-%M-%S")
media_item['end'] = datetime.strptime(media_item['end'],
"%Y-%m-%d-%H-%M-%S")
media_copy[key] = media_item
self.media_prepare_queue.put(copy.copy(media_filtered))

View file

@ -63,14 +63,6 @@ class PypoFile(Thread):
self.logger.debug("copying from %s to local cache %s" % (src, dst))
try:
"""
List file as "ready" before it starts copying because by the time
Liquidsoap is ready to play this file, it should have at least started
copying (and can continue copying while Liquidsoap reads from the beginning
of the file)
"""
media_item['file_ready'] = True
"""
copy will overwrite dst if it already exists
"""
@ -78,6 +70,8 @@ class PypoFile(Thread):
#make file world readable
os.chmod(dst, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
media_item['file_ready'] = True
except Exception, e:
self.logger.error("Could not copy from %s to %s" % (src, dst))
self.logger.error(e)

View file

@ -61,8 +61,10 @@ class PypoLiqQueue(Thread):
schedule_deque.append(media_schedule[i])
if len(keys):
time_until_next_play = self.date_interval_to_seconds(\
keys[0] - datetime.utcnow())
time_until_next_play = self.date_interval_to_seconds(
media_schedule[keys[0]]['start'] -
datetime.utcnow())
else:
time_until_next_play = None

View file

@ -2,6 +2,7 @@
from datetime import datetime
from datetime import timedelta
from configobj import ConfigObj
import sys
import time
@ -21,7 +22,7 @@ from threading import Thread
from api_clients import api_client
from std_err_override import LogWriter
from configobj import ConfigObj
from timeout import ls_timeout
# configure logging
@ -110,48 +111,10 @@ class PypoPush(Thread):
if diff_sec >= 0:
present.append(media_item)
else:
future[media_item['start']] = media_item
future[mkey] = media_item
return present, future
def get_current_stream_id_from_liquidsoap(self):
response = "-1"
try:
self.telnet_lock.acquire()
tn = telnetlib.Telnet(self.config['ls_host'], self.config['ls_port'])
msg = 'dynamic_source.get_id\n'
tn.write(msg)
response = tn.read_until("\r\n").strip(" \r\n")
tn.write('exit\n')
tn.read_all()
except Exception, e:
self.logger.error("Error connecting to Liquidsoap: %s", e)
response = []
finally:
self.telnet_lock.release()
return response
#def is_correct_current_item(self, media_item, liquidsoap_queue_approx, liquidsoap_stream_id):
#correct = False
#if media_item is None:
#correct = (len(liquidsoap_queue_approx) == 0 and liquidsoap_stream_id == "-1")
#else:
#if is_file(media_item):
#if len(liquidsoap_queue_approx) == 0:
#correct = False
#else:
#correct = liquidsoap_queue_approx[0]['start'] == media_item['start'] and \
#liquidsoap_queue_approx[0]['row_id'] == media_item['row_id'] and \
#liquidsoap_queue_approx[0]['end'] == media_item['end'] and \
#liquidsoap_queue_approx[0]['replay_gain'] == media_item['replay_gain']
#elif is_stream(media_item):
#correct = liquidsoap_stream_id == str(media_item['row_id'])
#self.logger.debug("Is current item correct?: %s", str(correct))
#return correct
def date_interval_to_seconds(self, interval):
"""
Convert timedelta object into int representing the number of seconds. If
@ -162,6 +125,7 @@ class PypoPush(Thread):
return seconds
@ls_timeout
def stop_web_stream_all(self):
try:
self.telnet_lock.acquire()

View file

@ -1,4 +1,5 @@
import telnetlib
from timeout import ls_timeout
def create_liquidsoap_annotation(media):
# We need liq_start_next value in the annotate. That is the value that controls overlap duration of crossfade.
@ -38,6 +39,7 @@ class TelnetLiquidsoap:
else:
raise Exception("Unexpected list length returned: %s" % output)
@ls_timeout
def queue_clear_all(self):
try:
self.telnet_lock.acquire()
@ -55,6 +57,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def queue_remove(self, queue_id):
try:
self.telnet_lock.acquire()
@ -72,6 +75,7 @@ class TelnetLiquidsoap:
self.telnet_lock.release()
@ls_timeout
def queue_push(self, queue_id, media_item):
try:
self.telnet_lock.acquire()
@ -98,6 +102,7 @@ class TelnetLiquidsoap:
self.telnet_lock.release()
@ls_timeout
def stop_web_stream_buffer(self):
try:
self.telnet_lock.acquire()
@ -120,6 +125,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def stop_web_stream_output(self):
try:
self.telnet_lock.acquire()
@ -138,6 +144,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def start_web_stream(self, media_item):
try:
self.telnet_lock.acquire()
@ -160,6 +167,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def start_web_stream_buffer(self, media_item):
try:
self.telnet_lock.acquire()
@ -182,6 +190,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def get_current_stream_id(self):
try:
self.telnet_lock.acquire()
@ -201,6 +210,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def disconnect_source(self, sourcename):
self.logger.debug('Disconnecting source: %s', sourcename)
command = ""
@ -221,6 +231,7 @@ class TelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def telnet_send(self, commands):
try:
self.telnet_lock.acquire()
@ -265,6 +276,7 @@ class DummyTelnetLiquidsoap:
for i in range(4):
self.liquidsoap_mock_queues["s"+str(i)] = []
@ls_timeout
def queue_push(self, queue_id, media_item):
try:
self.telnet_lock.acquire()
@ -280,6 +292,7 @@ class DummyTelnetLiquidsoap:
finally:
self.telnet_lock.release()
@ls_timeout
def queue_remove(self, queue_id):
try:
self.telnet_lock.acquire()

View file

@ -0,0 +1,36 @@
import threading
import pypofetch
def __timeout(func, timeout_duration, default, args, kwargs):
class InterruptableThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.result = default
def run(self):
self.result = func(*args, **kwargs)
first_attempt = True
while True:
it = InterruptableThread()
it.start()
it.join(timeout_duration)
if it.isAlive():
"""Restart Liquidsoap and try the command one more time. If it
fails again then there is something critically wrong..."""
if first_attempt:
#restart liquidsoap
pypofetch.PypoFetch.ref.restart_liquidsoap()
else:
raise Exception("Thread did not terminate")
else:
return it.result
first_attempt = False
def ls_timeout(f, timeout=4, default=None):
def new_f(*args, **kwargs):
return __timeout(f, timeout, default, args, kwargs)
return new_f