Merge branch '2.4.x'
Conflicts: airtime_mvc/public/js/airtime/showbuilder/builder.js python_apps/pypo/liquidsoap_scripts/fdkaac.liq python_apps/pypo/schedule/pypofetch.py python_apps/pypo/schedule/telnetliquidsoap.py
This commit is contained in:
commit
2a0c9769aa
40 changed files with 3341 additions and 3801 deletions
|
@ -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
|
||||
|
|
|
@ -4,6 +4,5 @@
|
|||
set httpd port 2812
|
||||
|
||||
check process airtime-liquidsoap with pidfile "/var/run/airtime-liquidsoap.pid"
|
||||
if does not exist for 3 cycles then restart
|
||||
start program = "/etc/init.d/airtime-liquidsoap start" with timeout 5 seconds
|
||||
stop program = "/etc/init.d/airtime-liquidsoap stop"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
if bitrate == 24 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 24), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 32 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 32), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 48 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 48), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 48, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 64 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 64), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 64, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 96 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 96), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 96, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 128 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 128), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 128, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 160 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 160), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 160, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 192 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 192), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 192, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 224 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 224), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 224, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 256 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 256), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 256, aot="mpeg4_he_aac_v2"), !source))
|
||||
elsif bitrate == 320 then
|
||||
ignore(output_stereo(%fdkaac(bitrate = 320), !source))
|
||||
ignore(output_stereo(%fdkaac(bitrate = 320, aot="mpeg4_he_aac_v2"), !source))
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,7 @@ 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",
|
||||
|
@ -70,6 +72,10 @@ create_source()
|
|||
|
||||
queue = add(!sources, normalize=false)
|
||||
|
||||
pair = insert_metadata(queue)
|
||||
dynamic_metadata_callback := fst(pair)
|
||||
queue = snd(pair)
|
||||
|
||||
output.dummy(fallible=true, queue)
|
||||
|
||||
http = input.http_restart(id="http")
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
@ -114,44 +115,6 @@ class PypoPush(Thread):
|
|||
|
||||
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()
|
||||
|
|
|
@ -34,6 +34,7 @@ from subprocess import Popen, PIPE
|
|||
|
||||
from api_clients import api_client
|
||||
from std_err_override import LogWriter
|
||||
from timeout import ls_timeout
|
||||
|
||||
import pure
|
||||
|
||||
|
@ -55,6 +56,8 @@ class PypoFetch(Thread):
|
|||
def __init__(self, pypoFetch_q, pypoPush_q, media_q, pypo_liquidsoap,
|
||||
config):
|
||||
Thread.__init__(self)
|
||||
#Hacky...
|
||||
PypoFetch.ref = self
|
||||
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
self.fetch_queue = pypoFetch_q
|
||||
|
@ -198,15 +201,23 @@ 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):
|
||||
self.logger.info("Restarting Liquidsoap")
|
||||
subprocess.call(['/etc/init.d/airtime-liquidsoap', 'restart'])
|
||||
self.telnet_lock.acquire(False)
|
||||
|
||||
#Wait here and poll Liquidsoap until it has started up
|
||||
self.logger.info("Waiting for Liquidsoap to start")
|
||||
self.pypo_liquidsoap.liquidsoap_startup_test()
|
||||
try:
|
||||
self.logger.info("Restarting Liquidsoap")
|
||||
subprocess.call(['/etc/init.d/airtime-liquidsoap', 'restart'])
|
||||
|
||||
#Wait here and poll Liquidsoap until it has started up
|
||||
self.logger.info("Waiting for Liquidsoap to start")
|
||||
self.pypo_liquidsoap.liquidsoap_startup_test()
|
||||
except Exception, e:
|
||||
self.logger.error(e)
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
"""
|
||||
TODO: This function needs to be way shorter, and refactored :/ - MK
|
||||
|
@ -306,6 +317,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
|
||||
|
@ -333,6 +345,7 @@ class PypoFetch(Thread):
|
|||
self.api_client.notify_liquidsoap_status("OK", stream_id,
|
||||
str(fake_time))
|
||||
|
||||
|
||||
"""
|
||||
Process the schedule
|
||||
- Reads the scheduled entries of a given range (actual time +/-
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"""
|
||||
import telnetlib
|
||||
from threading import Lock
|
||||
from timeout import ls_timeout
|
||||
|
||||
def create_liquidsoap_annotation(media):
|
||||
# We need liq_start_next value in the annotate. That is the value that
|
||||
|
@ -48,6 +49,7 @@ class TelnetLiquidsoap:
|
|||
else:
|
||||
raise Exception("Unexpected list length returned: %s" % output)
|
||||
|
||||
@ls_timeout
|
||||
def queue_clear_all(self):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -60,6 +62,7 @@ class TelnetLiquidsoap:
|
|||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
@ls_timeout
|
||||
def queue_remove(self, queue_id):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -71,6 +74,7 @@ class TelnetLiquidsoap:
|
|||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
@ls_timeout
|
||||
def queue_push(self, queue_id, media_item):
|
||||
with self.telnet_lock:
|
||||
if not self.__is_empty(queue_id):
|
||||
|
@ -90,6 +94,7 @@ class TelnetLiquidsoap:
|
|||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
@ls_timeout
|
||||
def stop_web_stream_buffer(self):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -105,6 +110,7 @@ class TelnetLiquidsoap:
|
|||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
@ls_timeout
|
||||
def stop_web_stream_output(self):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -116,6 +122,8 @@ class TelnetLiquidsoap:
|
|||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
|
||||
@ls_timeout
|
||||
def start_web_stream(self, media_item):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -133,6 +141,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
self.current_prebuffering_stream_id = None
|
||||
|
||||
@ls_timeout
|
||||
def start_web_stream_buffer(self, media_item):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -150,6 +159,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
self.current_prebuffering_stream_id = media_item['row_id']
|
||||
|
||||
@ls_timeout
|
||||
def get_current_stream_id(self):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -164,6 +174,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
return stream_id
|
||||
|
||||
@ls_timeout
|
||||
def disconnect_source(self, sourcename):
|
||||
self.logger.debug('Disconnecting source: %s', sourcename)
|
||||
command = ""
|
||||
|
@ -179,6 +190,7 @@ class TelnetLiquidsoap:
|
|||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
|
||||
@ls_timeout
|
||||
def telnet_send(self, commands):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -189,6 +201,7 @@ class TelnetLiquidsoap:
|
|||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
|
||||
@ls_timeout
|
||||
def switch_source(self, sourcename, status):
|
||||
self.logger.debug('Switching source: %s to "%s" status', sourcename,
|
||||
status)
|
||||
|
@ -207,6 +220,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
self.telnet_send([command])
|
||||
|
||||
@ls_timeout
|
||||
def liquidsoap_get_info(self):
|
||||
self.logger.debug("Checking to see if Liquidsoap is running")
|
||||
response = ""
|
||||
|
@ -219,6 +233,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
return response
|
||||
|
||||
@ls_timeout
|
||||
def update_liquidsoap_station_name(self, station_name):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -229,6 +244,7 @@ class TelnetLiquidsoap:
|
|||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
|
||||
@ls_timeout
|
||||
def get_liquidsoap_connection_status(self, current_time):
|
||||
output = None
|
||||
with self.telnet_lock:
|
||||
|
@ -249,6 +265,7 @@ class TelnetLiquidsoap:
|
|||
|
||||
return output
|
||||
|
||||
@ls_timeout
|
||||
def update_liquidsoap_stream_format(self, stream_format):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -259,6 +276,7 @@ class TelnetLiquidsoap:
|
|||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
|
||||
@ls_timeout
|
||||
def update_liquidsoap_transition_fade(self, fade):
|
||||
with self.telnet_lock:
|
||||
tn = self.__connect()
|
||||
|
@ -278,6 +296,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()
|
||||
|
@ -293,6 +312,7 @@ class DummyTelnetLiquidsoap:
|
|||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
@ls_timeout
|
||||
def queue_remove(self, queue_id):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
|
|
36
python_apps/pypo/timeout.py
Normal file
36
python_apps/pypo/timeout.py
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue