more pypo fixes
This commit is contained in:
parent
44a0cb50e1
commit
6ebb1fd555
|
@ -4,6 +4,8 @@ curl
|
||||||
ecasound
|
ecasound
|
||||||
flac
|
flac
|
||||||
git
|
git
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly
|
gstreamer1.0-plugins-ugly
|
||||||
icecast2
|
icecast2
|
||||||
lame
|
lame
|
||||||
|
|
|
@ -4,6 +4,8 @@ curl
|
||||||
ecasound
|
ecasound
|
||||||
flac
|
flac
|
||||||
git
|
git
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly
|
gstreamer1.0-plugins-ugly
|
||||||
icecast2
|
icecast2
|
||||||
lame
|
lame
|
||||||
|
|
|
@ -4,6 +4,8 @@ coreutils
|
||||||
curl
|
curl
|
||||||
ecasound
|
ecasound
|
||||||
flac
|
flac
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly
|
gstreamer1.0-plugins-ugly
|
||||||
icecast2
|
icecast2
|
||||||
lame
|
lame
|
||||||
|
|
|
@ -4,6 +4,8 @@ coreutils
|
||||||
curl
|
curl
|
||||||
ecasound
|
ecasound
|
||||||
flac
|
flac
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly
|
gstreamer1.0-plugins-ugly
|
||||||
icecast2
|
icecast2
|
||||||
lame
|
lame
|
||||||
|
|
|
@ -4,6 +4,8 @@ coreutils
|
||||||
curl
|
curl
|
||||||
ecasound
|
ecasound
|
||||||
flac
|
flac
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly
|
gstreamer1.0-plugins-ugly
|
||||||
lame
|
lame
|
||||||
libao-ocaml
|
libao-ocaml
|
||||||
|
|
|
@ -117,7 +117,8 @@ class ApiRequest(object):
|
||||||
|
|
||||||
def __call__(self,_post_data=None, **kwargs):
|
def __call__(self,_post_data=None, **kwargs):
|
||||||
final_url = self.url.params(**kwargs).url()
|
final_url = self.url.params(**kwargs).url()
|
||||||
if _post_data is not None: _post_data = urllib.parse.urlencode(_post_data)
|
if _post_data is not None:
|
||||||
|
_post_data = urllib.parse.urlencode(_post_data).encode('utf-8')
|
||||||
self.logger.debug(final_url)
|
self.logger.debug(final_url)
|
||||||
try:
|
try:
|
||||||
req = urllib.request.Request(final_url, _post_data)
|
req = urllib.request.Request(final_url, _post_data)
|
||||||
|
@ -131,8 +132,7 @@ class ApiRequest(object):
|
||||||
self.logger.error('HTTP request to %s timed out', final_url)
|
self.logger.error('HTTP request to %s timed out', final_url)
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#self.logger.error('Exception: %s', e)
|
#self.logger.exception(e)
|
||||||
#self.logger.error("traceback: %s", traceback.format_exc())
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -142,8 +142,7 @@ class ApiRequest(object):
|
||||||
else:
|
else:
|
||||||
raise InvalidContentType()
|
raise InvalidContentType()
|
||||||
except Exception:
|
except Exception:
|
||||||
#self.logger.error(response)
|
#self.logger.exception(e)
|
||||||
#self.logger.error("traceback: %s", traceback.format_exc())
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def req(self, *args, **kwargs):
|
def req(self, *args, **kwargs):
|
||||||
|
@ -182,8 +181,10 @@ class RequestProvider(object):
|
||||||
def __contains__(self, request) : return request in self.requests
|
def __contains__(self, request) : return request in self.requests
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr in self: return self.requests[attr]
|
if attr in self:
|
||||||
else: return super(RequestProvider, self).__getattribute__(attr)
|
return self.requests[attr]
|
||||||
|
else:
|
||||||
|
return super(RequestProvider, self).__getattribute__(attr)
|
||||||
|
|
||||||
|
|
||||||
class AirtimeApiClient(object):
|
class AirtimeApiClient(object):
|
||||||
|
@ -197,8 +198,7 @@ class AirtimeApiClient(object):
|
||||||
self.config.update(api_config)
|
self.config.update(api_config)
|
||||||
self.services = RequestProvider(self.config)
|
self.services = RequestProvider(self.config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error('Error loading config file: %s', config_path)
|
self.logger.exception('Error loading config file: %s', config_path)
|
||||||
self.logger.error("traceback: %s", traceback.format_exc())
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def __get_airtime_version(self):
|
def __get_airtime_version(self):
|
||||||
|
@ -239,7 +239,7 @@ class AirtimeApiClient(object):
|
||||||
try:
|
try:
|
||||||
self.services.notify_liquidsoap_started()
|
self.services.notify_liquidsoap_started()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
|
|
||||||
def notify_media_item_start_playing(self, media_id):
|
def notify_media_item_start_playing(self, media_id):
|
||||||
""" This is a callback from liquidsoap, we use this to notify
|
""" This is a callback from liquidsoap, we use this to notify
|
||||||
|
@ -248,14 +248,14 @@ class AirtimeApiClient(object):
|
||||||
try:
|
try:
|
||||||
return self.services.update_start_playing_url(media_id=media_id)
|
return self.services.update_start_playing_url(media_id=media_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_shows_to_record(self):
|
def get_shows_to_record(self):
|
||||||
try:
|
try:
|
||||||
return self.services.show_schedule_url()
|
return self.services.show_schedule_url()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def upload_recorded_show(self, files, show_id):
|
def upload_recorded_show(self, files, show_id):
|
||||||
|
@ -307,8 +307,7 @@ class AirtimeApiClient(object):
|
||||||
logger.error("Server is down: %s", e.args)
|
logger.error("Server is down: %s", e.args)
|
||||||
logger.error("traceback: %s", traceback.format_exc())
|
logger.error("traceback: %s", traceback.format_exc())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Exception: %s", e)
|
self.logger.exception(e)
|
||||||
logger.error("traceback: %s", traceback.format_exc())
|
|
||||||
|
|
||||||
#wait some time before next retry
|
#wait some time before next retry
|
||||||
time.sleep(retries_wait)
|
time.sleep(retries_wait)
|
||||||
|
@ -320,7 +319,7 @@ class AirtimeApiClient(object):
|
||||||
return self.services.check_live_stream_auth(
|
return self.services.check_live_stream_auth(
|
||||||
username=username, password=password, djtype=dj_type)
|
username=username, password=password, djtype=dj_type)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def construct_url(self,config_action_key):
|
def construct_url(self,config_action_key):
|
||||||
|
@ -468,17 +467,14 @@ class AirtimeApiClient(object):
|
||||||
stream_id=stream_id,
|
stream_id=stream_id,
|
||||||
boot_time=time).retry(5)
|
boot_time=time).retry(5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#TODO
|
self.logger.exception(e)
|
||||||
logger.error("Exception: %s", e)
|
|
||||||
|
|
||||||
def notify_source_status(self, sourcename, status):
|
def notify_source_status(self, sourcename, status):
|
||||||
try:
|
try:
|
||||||
logger = self.logger
|
|
||||||
return self.services.update_source_status.req(sourcename=sourcename,
|
return self.services.update_source_status.req(sourcename=sourcename,
|
||||||
status=status).retry(5)
|
status=status).retry(5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#TODO
|
self.logger.exception(e)
|
||||||
logger.error("Exception: %s", e)
|
|
||||||
|
|
||||||
def get_bootstrap_info(self):
|
def get_bootstrap_info(self):
|
||||||
""" Retrieve infomations needed on bootstrap time """
|
""" Retrieve infomations needed on bootstrap time """
|
||||||
|
@ -494,7 +490,7 @@ class AirtimeApiClient(object):
|
||||||
try:
|
try:
|
||||||
return self.services.get_files_without_replay_gain(dir_id=dir_id)
|
return self.services.get_files_without_replay_gain(dir_id=dir_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get_files_without_silan_value(self):
|
def get_files_without_silan_value(self):
|
||||||
|
@ -506,7 +502,7 @@ class AirtimeApiClient(object):
|
||||||
try:
|
try:
|
||||||
return self.services.get_files_without_silan_value()
|
return self.services.get_files_without_silan_value()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def update_replay_gain_values(self, pairs):
|
def update_replay_gain_values(self, pairs):
|
||||||
|
@ -549,8 +545,7 @@ class AirtimeApiClient(object):
|
||||||
response = self.services.update_stream_setting_table(_post_data={'data': json.dumps(data)})
|
response = self.services.update_stream_setting_table(_post_data={'data': json.dumps(data)})
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#TODO
|
self.logger.exception(e)
|
||||||
self.logger.error(str(e))
|
|
||||||
|
|
||||||
def update_metadata_on_tunein(self):
|
def update_metadata_on_tunein(self):
|
||||||
self.services.update_metadata_on_tunein()
|
self.services.update_metadata_on_tunein()
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
""" Runs Airtime liquidsoap
|
""" Runs Airtime liquidsoap
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
from . import generate_liquidsoap_cfg
|
from . import generate_liquidsoap_cfg
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from pypo import pure
|
||||||
|
|
||||||
PYPO_HOME = '/var/tmp/airtime/pypo/'
|
PYPO_HOME = '/var/tmp/airtime/pypo/'
|
||||||
|
|
||||||
|
@ -16,16 +15,16 @@ def run():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("-d", "--debug", help="run in debug mode", action="store_true")
|
parser.add_argument("-d", "--debug", help="run in debug mode", action="store_true")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
os.environ["HOME"] = PYPO_HOME
|
os.environ["HOME"] = PYPO_HOME
|
||||||
|
|
||||||
if args.debug:
|
if args.debug:
|
||||||
logging.basicConfig(level=getattr(logging, 'DEBUG', None))
|
logging.basicConfig(level=getattr(logging, 'DEBUG', None))
|
||||||
|
|
||||||
generate_liquidsoap_cfg.run()
|
generate_liquidsoap_cfg.run()
|
||||||
''' check liquidsoap version if less than 1.3 use legacy liquidsoap script '''
|
''' check liquidsoap version if less than 1.3 use legacy liquidsoap script '''
|
||||||
liquidsoap_version=subprocess.check_output("liquidsoap --version", shell=True)
|
liquidsoap_version = subprocess.check_output("liquidsoap --version", shell=True, text=True)
|
||||||
if "1.1.1" not in liquidsoap_version:
|
if pure.version_cmp(liquidsoap_version, "1.3") < 0:
|
||||||
script_path = os.path.join(os.path.dirname(__file__), 'ls_script.liq')
|
script_path = os.path.join(os.path.dirname(__file__), 'ls_script.liq')
|
||||||
else:
|
else:
|
||||||
script_path = os.path.join(os.path.dirname(__file__), 'ls_script_legacy.liq')
|
script_path = os.path.join(os.path.dirname(__file__), 'ls_script_legacy.liq')
|
||||||
|
|
|
@ -28,21 +28,21 @@ def generate_liquidsoap_config(ss):
|
||||||
except: #Everything else is a string
|
except: #Everything else is a string
|
||||||
str_buffer = "%s = \"%s\"\n" % (key, value)
|
str_buffer = "%s = \"%s\"\n" % (key, value)
|
||||||
|
|
||||||
fh.write(str_buffer.encode('utf-8'))
|
fh.write(str_buffer)
|
||||||
# ignore squashes unused variable errors from Liquidsoap
|
# ignore squashes unused variable errors from Liquidsoap
|
||||||
fh.write(("ignore(%s)\n" % key).encode('utf-8'))
|
fh.write("ignore(%s)\n" % key)
|
||||||
|
|
||||||
auth_path = os.path.dirname(os.path.realpath(__file__))
|
auth_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
|
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
|
||||||
fh.write('auth_path = "%s/liquidsoap_auth.py"\n' % auth_path)
|
fh.write('auth_path = "%s/liquidsoap_auth.py"\n' % auth_path)
|
||||||
fh.close()
|
fh.close()
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
logging.basicConfig(format='%(message)s')
|
logging.basicConfig(format='%(message)s')
|
||||||
attempts = 0
|
attempts = 0
|
||||||
max_attempts = 10
|
max_attempts = 10
|
||||||
successful = False
|
successful = False
|
||||||
|
|
||||||
while not successful:
|
while not successful:
|
||||||
try:
|
try:
|
||||||
ac = AirtimeApiClient(logging.getLogger())
|
ac = AirtimeApiClient(logging.getLogger())
|
||||||
|
|
|
@ -155,11 +155,11 @@ def liquidsoap_get_info(telnet_lock, host, port, logger):
|
||||||
telnet_lock.acquire()
|
telnet_lock.acquire()
|
||||||
tn = telnetlib.Telnet(host, port)
|
tn = telnetlib.Telnet(host, port)
|
||||||
msg = "version\n"
|
msg = "version\n"
|
||||||
tn.write(msg)
|
tn.write(msg.encode("utf-8"))
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode("utf-8"))
|
||||||
response = tn.read_all()
|
response = tn.read_all().decode("utf-8")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(str(e))
|
logger.error(e)
|
||||||
return None
|
return None
|
||||||
finally:
|
finally:
|
||||||
telnet_lock.release()
|
telnet_lock.release()
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import re
|
import re
|
||||||
|
from packaging.version import Version, parse
|
||||||
|
|
||||||
def version_cmp(version1, version2):
|
def version_cmp(version1, version2):
|
||||||
def normalize(v):
|
version1 = parse(version1)
|
||||||
return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
|
version2 = parse(version2)
|
||||||
return cmp(normalize(version1), normalize(version2))
|
if version1 > version2:
|
||||||
|
return 1
|
||||||
|
if version1 == version2:
|
||||||
|
return 0
|
||||||
|
return -1
|
||||||
|
|
||||||
def date_interval_to_seconds(interval):
|
def date_interval_to_seconds(interval):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -10,9 +10,8 @@ import copy
|
||||||
import subprocess
|
import subprocess
|
||||||
import signal
|
import signal
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import traceback
|
|
||||||
from . import pure
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
from . import pure
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
from threading import Thread, Timer
|
from threading import Thread, Timer
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
@ -121,10 +120,7 @@ class PypoFetch(Thread):
|
||||||
self.listener_timeout = 0
|
self.listener_timeout = 0
|
||||||
self.logger.info("New timeout: %s" % self.listener_timeout)
|
self.logger.info("New timeout: %s" % self.listener_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
top = traceback.format_exc()
|
self.logger.exception("Exception in handling Message Handler message")
|
||||||
self.logger.error('Exception: %s', e)
|
|
||||||
self.logger.error("traceback: %s", top)
|
|
||||||
self.logger.error("Exception in handling Message Handler message: %s", e)
|
|
||||||
|
|
||||||
|
|
||||||
def switch_source_temp(self, sourcename, status):
|
def switch_source_temp(self, sourcename, status):
|
||||||
|
@ -152,8 +148,7 @@ class PypoFetch(Thread):
|
||||||
try:
|
try:
|
||||||
info = self.api_client.get_bootstrap_info()
|
info = self.api_client.get_bootstrap_info()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error('Unable to get bootstrap info.. Exiting pypo...')
|
self.logger.exception('Unable to get bootstrap info.. Exiting pypo...')
|
||||||
self.logger.error(str(e))
|
|
||||||
|
|
||||||
self.logger.debug('info:%s', info)
|
self.logger.debug('info:%s', info)
|
||||||
commands = []
|
commands = []
|
||||||
|
@ -199,7 +194,7 @@ class PypoFetch(Thread):
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
if self.telnet_lock.locked():
|
if self.telnet_lock.locked():
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
|
@ -238,7 +233,7 @@ class PypoFetch(Thread):
|
||||||
|
|
||||||
output = tn.read_all()
|
output = tn.read_all()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
|
|
||||||
|
@ -272,7 +267,7 @@ class PypoFetch(Thread):
|
||||||
tn.write('exit\n')
|
tn.write('exit\n')
|
||||||
tn.read_all()
|
tn.read_all()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("Exception %s", e)
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
|
|
||||||
|
@ -289,7 +284,7 @@ class PypoFetch(Thread):
|
||||||
tn.write('exit\n')
|
tn.write('exit\n')
|
||||||
tn.read_all()
|
tn.read_all()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("Exception %s", e)
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
|
|
||||||
|
@ -307,11 +302,11 @@ class PypoFetch(Thread):
|
||||||
tn.write('exit\n')
|
tn.write('exit\n')
|
||||||
tn.read_all()
|
tn.read_all()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("Exception %s", e)
|
self.logger.exception(e)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Process the schedule
|
Process the schedule
|
||||||
|
@ -344,7 +339,7 @@ class PypoFetch(Thread):
|
||||||
media_item = media[key]
|
media_item = media[key]
|
||||||
if (media_item['type'] == 'file'):
|
if (media_item['type'] == 'file'):
|
||||||
fileExt = self.sanity_check_media_item(media_item)
|
fileExt = self.sanity_check_media_item(media_item)
|
||||||
dst = os.path.join(download_dir, media_item['id'] + fileExt)
|
dst = os.path.join(download_dir, "{}{}".format(media_item['id'], fileExt))
|
||||||
media_item['dst'] = dst
|
media_item['dst'] = dst
|
||||||
media_item['file_ready'] = False
|
media_item['file_ready'] = False
|
||||||
media_filtered[key] = media_item
|
media_filtered[key] = media_item
|
||||||
|
@ -358,7 +353,7 @@ class PypoFetch(Thread):
|
||||||
|
|
||||||
self.media_prepare_queue.put(copy.copy(media_filtered))
|
self.media_prepare_queue.put(copy.copy(media_filtered))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.exception(e)
|
||||||
|
|
||||||
# Send the data to pypo-push
|
# Send the data to pypo-push
|
||||||
self.logger.debug("Pushing to pypo-push")
|
self.logger.debug("Pushing to pypo-push")
|
||||||
|
@ -369,7 +364,7 @@ class PypoFetch(Thread):
|
||||||
try:
|
try:
|
||||||
self.cache_cleanup(media)
|
self.cache_cleanup(media)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.exception(e)
|
||||||
|
|
||||||
#do basic validation of file parameters. Useful for debugging
|
#do basic validation of file parameters. Useful for debugging
|
||||||
#purposes
|
#purposes
|
||||||
|
@ -411,7 +406,9 @@ class PypoFetch(Thread):
|
||||||
for mkey in media:
|
for mkey in media:
|
||||||
media_item = media[mkey]
|
media_item = media[mkey]
|
||||||
if media_item['type'] == 'file':
|
if media_item['type'] == 'file':
|
||||||
scheduled_file_set.add(media_item["id"] + media_item["file_ext"])
|
if "file_ext" not in media_item.keys():
|
||||||
|
media_item["file_ext"] = mimetypes.guess_extension(media_item['metadata']['mime'], strict=False)
|
||||||
|
scheduled_file_set.add("{}{}".format(media_item["id"], media_item["file_ext"]))
|
||||||
|
|
||||||
expired_files = cached_file_set - scheduled_file_set
|
expired_files = cached_file_set - scheduled_file_set
|
||||||
|
|
||||||
|
@ -430,8 +427,7 @@ class PypoFetch(Thread):
|
||||||
else:
|
else:
|
||||||
self.logger.info("File '%s' not removed. Still busy!" % path)
|
self.logger.info("File '%s' not removed. Still busy!" % path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("Problem removing file '%s'" % f)
|
self.logger.exception("Problem removing file '%s'" % f)
|
||||||
self.logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
def manual_schedule_fetch(self):
|
def manual_schedule_fetch(self):
|
||||||
success, self.schedule_data = self.api_client.get_schedule()
|
success, self.schedule_data = self.api_client.get_schedule()
|
||||||
|
@ -501,18 +497,13 @@ class PypoFetch(Thread):
|
||||||
self.logger.info("Queue timeout. Fetching schedule manually")
|
self.logger.info("Queue timeout. Fetching schedule manually")
|
||||||
manual_fetch_needed = True
|
manual_fetch_needed = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
top = traceback.format_exc()
|
self.logger.exception(e)
|
||||||
self.logger.error('Exception: %s', e)
|
|
||||||
self.logger.error("traceback: %s", top)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if manual_fetch_needed:
|
if manual_fetch_needed:
|
||||||
self.persistent_manual_schedule_fetch(max_attempts=5)
|
self.persistent_manual_schedule_fetch(max_attempts=5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
top = traceback.format_exc()
|
self.logger.exception('Failed to manually fetch the schedule.')
|
||||||
self.logger.error('Failed to manually fetch the schedule.')
|
|
||||||
self.logger.error('Exception: %s', e)
|
|
||||||
self.logger.error("traceback: %s", top)
|
|
||||||
|
|
||||||
loops += 1
|
loops += 1
|
||||||
|
|
||||||
|
|
|
@ -97,26 +97,28 @@ class PypoLiquidsoap():
|
||||||
|
|
||||||
|
|
||||||
def verify_correct_present_media(self, scheduled_now):
|
def verify_correct_present_media(self, scheduled_now):
|
||||||
#verify whether Liquidsoap is currently playing the correct files.
|
"""
|
||||||
#if we find an item that Liquidsoap is not playing, then push it
|
verify whether Liquidsoap is currently playing the correct files.
|
||||||
#into one of Liquidsoap's queues. If Liquidsoap is already playing
|
if we find an item that Liquidsoap is not playing, then push it
|
||||||
#it do nothing. If Liquidsoap is playing a track that isn't in
|
into one of Liquidsoap's queues. If Liquidsoap is already playing
|
||||||
#currently_playing then stop it.
|
it do nothing. If Liquidsoap is playing a track that isn't in
|
||||||
|
currently_playing then stop it.
|
||||||
|
|
||||||
#Check for Liquidsoap media we should source.skip
|
Check for Liquidsoap media we should source.skip
|
||||||
#get liquidsoap items for each queue. Since each queue can only have one
|
get liquidsoap items for each queue. Since each queue can only have one
|
||||||
#item, we should have a max of 8 items.
|
item, we should have a max of 8 items.
|
||||||
|
|
||||||
#2013-03-21-22-56-00_0: {
|
2013-03-21-22-56-00_0: {
|
||||||
#id: 1,
|
id: 1,
|
||||||
#type: "stream_output_start",
|
type: "stream_output_start",
|
||||||
#row_id: 41,
|
row_id: 41,
|
||||||
#uri: "http://stream2.radioblackout.org:80/blackout.ogg",
|
uri: "http://stream2.radioblackout.org:80/blackout.ogg",
|
||||||
#start: "2013-03-21-22-56-00",
|
start: "2013-03-21-22-56-00",
|
||||||
#end: "2013-03-21-23-26-00",
|
end: "2013-03-21-23-26-00",
|
||||||
#show_name: "Untitled Show",
|
show_name: "Untitled Show",
|
||||||
#independent_event: true
|
independent_event: true
|
||||||
#},
|
},
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
scheduled_now_files = \
|
scheduled_now_files = \
|
||||||
|
@ -125,7 +127,7 @@ class PypoLiquidsoap():
|
||||||
scheduled_now_webstream = \
|
scheduled_now_webstream = \
|
||||||
[x for x in scheduled_now if x["type"] == eventtypes.STREAM_OUTPUT_START]
|
[x for x in scheduled_now if x["type"] == eventtypes.STREAM_OUTPUT_START]
|
||||||
|
|
||||||
schedule_ids = [x["row_id"] for x in scheduled_now_files]
|
schedule_ids = set([x["row_id"] for x in scheduled_now_files])
|
||||||
|
|
||||||
row_id_map = {}
|
row_id_map = {}
|
||||||
liq_queue_ids = set()
|
liq_queue_ids = set()
|
||||||
|
@ -155,7 +157,6 @@ class PypoLiquidsoap():
|
||||||
to_be_removed.add(i["row_id"])
|
to_be_removed.add(i["row_id"])
|
||||||
to_be_added.add(i["row_id"])
|
to_be_added.add(i["row_id"])
|
||||||
|
|
||||||
|
|
||||||
to_be_removed.update(liq_queue_ids - schedule_ids)
|
to_be_removed.update(liq_queue_ids - schedule_ids)
|
||||||
to_be_added.update(schedule_ids - liq_queue_ids)
|
to_be_added.update(schedule_ids - liq_queue_ids)
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ class TelnetLiquidsoap:
|
||||||
return True
|
return True
|
||||||
tn = self.__connect()
|
tn = self.__connect()
|
||||||
msg = '%s.queue\nexit\n' % queue_id
|
msg = '%s.queue\nexit\n' % queue_id
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
output = tn.read_all().splitlines()
|
output = tn.read_all().decode('utf-8').splitlines()
|
||||||
if len(output) == 3:
|
if len(output) == 3:
|
||||||
return len(output[0]) == 0
|
return len(output[0]) == 0
|
||||||
else:
|
else:
|
||||||
|
@ -68,10 +68,10 @@ class TelnetLiquidsoap:
|
||||||
for i in self.queues:
|
for i in self.queues:
|
||||||
msg = 'queues.%s_skip\n' % i
|
msg = 'queues.%s_skip\n' % i
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
|
@ -85,10 +85,10 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
msg = 'queues.%s_skip\n' % queue_id
|
msg = 'queues.%s_skip\n' % queue_id
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
|
@ -105,17 +105,17 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
tn = self.__connect()
|
tn = self.__connect()
|
||||||
annotation = create_liquidsoap_annotation(media_item)
|
annotation = create_liquidsoap_annotation(media_item)
|
||||||
msg = '%s.push %s\n' % (queue_id, annotation.encode('utf-8'))
|
msg = '%s.push %s\n' % (queue_id, annotation)
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
show_name = media_item['show_name']
|
show_name = media_item['show_name']
|
||||||
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
msg = 'vars.show_name %s\n' % show_name
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
|
@ -131,14 +131,14 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
msg = 'http.stop\n'
|
msg = 'http.stop\n'
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
msg = 'dynamic_source.id -1\n'
|
msg = 'dynamic_source.id -1\n'
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
|
@ -154,10 +154,10 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
msg = 'dynamic_source.output_stop\n'
|
msg = 'dynamic_source.output_stop\n'
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
|
@ -172,21 +172,21 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
#TODO: DO we need this?
|
#TODO: DO we need this?
|
||||||
msg = 'streams.scheduled_play_start\n'
|
msg = 'streams.scheduled_play_start\n'
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
msg = 'dynamic_source.output_start\n'
|
msg = 'dynamic_source.output_start\n'
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
|
|
||||||
self.current_prebuffering_stream_id = None
|
self.current_prebuffering_stream_id = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
finally:
|
finally:
|
||||||
self.telnet_lock.release()
|
self.telnet_lock.release()
|
||||||
|
|
||||||
@ls_timeout
|
@ls_timeout
|
||||||
def start_web_stream_buffer(self, media_item):
|
def start_web_stream_buffer(self, media_item):
|
||||||
try:
|
try:
|
||||||
|
@ -195,14 +195,14 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
msg = 'dynamic_source.id %s\n' % media_item['row_id']
|
msg = 'dynamic_source.id %s\n' % media_item['row_id']
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
msg = 'http.restart %s\n' % media_item['uri'].encode('latin-1')
|
msg = 'http.restart %s\n' % media_item['uri'].encode('latin-1')
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
self.logger.debug(tn.read_all())
|
self.logger.debug(tn.read_all().decode('utf-8'))
|
||||||
|
|
||||||
self.current_prebuffering_stream_id = media_item['row_id']
|
self.current_prebuffering_stream_id = media_item['row_id']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -218,10 +218,10 @@ class TelnetLiquidsoap:
|
||||||
|
|
||||||
msg = 'dynamic_source.get_id\n'
|
msg = 'dynamic_source.get_id\n'
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
tn.write(msg)
|
tn.write(msg.encode('utf-8'))
|
||||||
|
|
||||||
tn.write("exit\n")
|
tn.write("exit\n".encode('utf-8'))
|
||||||
stream_id = tn.read_all().splitlines()[0]
|
stream_id = tn.read_all().decode('utf-8').splitlines()[0]
|
||||||
self.logger.debug("stream_id: %s" % stream_id)
|
self.logger.debug("stream_id: %s" % stream_id)
|
||||||
|
|
||||||
return stream_id
|
return stream_id
|
||||||
|
@ -243,9 +243,9 @@ class TelnetLiquidsoap:
|
||||||
self.telnet_lock.acquire()
|
self.telnet_lock.acquire()
|
||||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||||
self.logger.info(command)
|
self.logger.info(command)
|
||||||
tn.write(command)
|
tn.write(command.encode('utf-8'))
|
||||||
tn.write('exit\n')
|
tn.write('exit\n'.encode('utf-8'))
|
||||||
tn.read_all()
|
tn.read_all().decode('utf-8')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(traceback.format_exc())
|
self.logger.error(traceback.format_exc())
|
||||||
finally:
|
finally:
|
||||||
|
@ -259,10 +259,10 @@ class TelnetLiquidsoap:
|
||||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||||
for i in commands:
|
for i in commands:
|
||||||
self.logger.info(i)
|
self.logger.info(i)
|
||||||
tn.write(i)
|
tn.write(i.encode('utf-8'))
|
||||||
|
|
||||||
tn.write('exit\n')
|
tn.write('exit\n'.encode('utf-8'))
|
||||||
tn.read_all()
|
tn.read_all().decode('utf-8')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -59,7 +59,8 @@ setup(name='airtime-playout',
|
||||||
'pyinotify',
|
'pyinotify',
|
||||||
'pytz',
|
'pytz',
|
||||||
'requests',
|
'requests',
|
||||||
'defusedxml'
|
'defusedxml',
|
||||||
|
'packaging',
|
||||||
],
|
],
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
data_files=data_files)
|
data_files=data_files)
|
||||||
|
|
Loading…
Reference in New Issue