diff --git a/aura.py b/aura.py index 97dd95be8b198447876748b1f07dbff64bcf4f5b..ad11739bde08cc90fa6987a6cc44738bc951263b 100755 --- a/aura.py +++ b/aura.py @@ -55,9 +55,10 @@ class Aura(AuraLogger): signal.signal(signal.SIGUSR1, receive_signal) + # wait for redis message self.join_comm() - # dafuq? when starting web service, logging messages appear twice + # start the web service self.start_web_service() def join_comm(self): diff --git a/configuration/engine.ini b/configuration/engine.ini index d951e29934ca256cad8f02f623e6197401e9e50e..c50c57bf7340d82011978ac4d933c5bf2730baa5 100644 --- a/configuration/engine.ini +++ b/configuration/engine.ini @@ -15,7 +15,7 @@ socketdir="/home/gg/PycharmProjects/engine/modules/liquidsoap" # if you change this settings, you have to restart liquidsoap logdir="/var/log/aura" # possible values: debug, info, warning, error, critical -loglevel="debug" +loglevel="info" [mail] mail_server="mail.servus.at" @@ -171,7 +171,7 @@ stream_0_channels="2" # to where we are streaming..? stream_0_host="localhost" # and which port? -stream_0_port="8000" +stream_0_port="8888" # the name of the mountpoint stream_0_mountpoint="aura-test-0.aac" # username @@ -193,7 +193,7 @@ stream_1_bitrate="128" stream_1_channels="2" stream_1_host="localhost" -stream_1_port="8000" +stream_1_port="8888" stream_1_mountpoint="aura-test-1.flac" stream_1_user="source" stream_1_password="source" @@ -209,7 +209,7 @@ stream_2_bitrate="64" stream_2_channels="2" stream_2_host="localhost" -stream_2_port="8000" +stream_2_port="8888" stream_2_mountpoint="aura-test-2.mp3" stream_2_user="source" stream_2_password="source" @@ -225,7 +225,7 @@ stream_3_bitrate="64" stream_3_channels="2" stream_3_host="localhost" -stream_3_port="8000" +stream_3_port="8888" stream_3_mountpoint="aura-test-3.ogg" stream_3_user="source" stream_3_password="source" @@ -241,7 +241,7 @@ stream_4_bitrate="64" stream_4_channels="2" stream_4_host="localhost" -stream_4_port="8000" +stream_4_port="8888" stream_4_mountpoint="aura-test-4.opus" stream_4_user="source" stream_4_password="source" diff --git a/libraries/database/broadcasts.py b/libraries/database/broadcasts.py index daba4c0953fbe098f2b6be3778761f688921cd19..e9c7b0e8cf4e28eede477d9c97b0f8d97a8fc29c 100644 --- a/libraries/database/broadcasts.py +++ b/libraries/database/broadcasts.py @@ -36,21 +36,22 @@ class AuraDatabaseModel: def _asdict(self): return self.__dict__ - def recreate_db(self, systemexit = False): + @staticmethod + def recreate_db(systemexit = False): manualschedule = Schedule() manualschedule.schedule_id = 0 manualschedule.show_name = "Manual Show" - self.logger.debug("Recreating Database...") +# self.logger.debug("Recreating Database...") DB.drop_all() - self.logger.debug("all dropped. creating...") +# self.logger.debug("all dropped. creating...") DB.create_all() - self.logger.debug("inserting manual scheduling possibility and fallback trackservice schedule") +# self.logger.debug("inserting manual scheduling possibility and fallback trackservice schedule") DB.session.add(manualschedule) # db.session.add(fallback_trackservice_schedule) - self.logger.debug("all created. commiting...") +# self.logger.debug("all created. commiting...") DB.session.commit() - self.logger.debug("Database recreated!") +# self.logger.debug("Database recreated!") if systemexit: sys.exit(0) @@ -65,13 +66,13 @@ class Schedule(DB.Model, AuraDatabaseModel): # primary and foreign keys schedule_id = Column(Integer, primary_key=True, autoincrement=False) - show_id = Column(Integer) # well, not needed.. + show_id = Column(Integer) # well, in fact not needed.. schedule_start = Column(DateTime) # can be null due to manual entries schedule_end = Column(DateTime) # can be null due to manual entries show_name = Column(String(256)) show_hosts = Column(String(256)) - rtr_category = Column(String(256)) + funding_category = Column(String(256)) comment = Column(String(512)) languages = Column(String(256)) type = Column(String(256)) @@ -295,4 +296,4 @@ class TrackService(DB.Model, AuraDatabaseModel): # def select_all(): # return db.session.query(TrackServiceScheduleEntry).filter().all() -#AuraDatabaseModel.recreate_db(True) +#AuraDatabaseModel.recreate_db(systemexit=True) diff --git a/modules/cli_tool/padavan.py b/modules/cli_tool/padavan.py index e5ef751de54f86ae4c9fca6dc3e4c0215b89974e..647877c6885a62b834ec295f57f84f9e8b53a9cf 100644 --- a/modules/cli_tool/padavan.py +++ b/modules/cli_tool/padavan.py @@ -117,8 +117,11 @@ class Padavan: def fetch_new_programme(self): json_reply = self.send_and_wait_redis("aura", "fetch_new_programme", RedisChannel.FNP_REPLY) - actprogramme = simplejson.loads(json_reply) - self.print_programme(actprogramme) + if json_reply != "": + actprogramme = simplejson.loads(json_reply) + self.print_programme(actprogramme) + else: + print("No programme fetched") def get_act_programme(self): json_reply = self.send_and_wait_redis("aura", "get_act_programme", RedisChannel.GAP_REPLY) diff --git a/modules/communication/liquidsoap/initthread.py b/modules/communication/liquidsoap/initthread.py index 687ea2265b9486738a16df57338c32cda057f1c4..f31f42d25f577214e18291cca2263ef97714091a 100644 --- a/modules/communication/liquidsoap/initthread.py +++ b/modules/communication/liquidsoap/initthread.py @@ -18,8 +18,8 @@ class LiquidSoapInitThread(threading.Thread): def run(self): try: # sleep needed, because the socket is created to slow by liquidsoap - time.sleep(2) - self.logger.info("Waited 2s for liquidsoap. Jez soit a si gspian") + time.sleep(1) + self.logger.info("Waited 1s for liquidsoap. Jez soit a si gspian") # enable lqs transaction self.liquidsoapcommunicator.enable_transaction() @@ -32,18 +32,18 @@ class LiquidSoapInitThread(threading.Thread): for c in channels: self.liquidsoapcommunicator.channel_volume(c, "0") - - # select all channels - for c in channels: - self.liquidsoapcommunicator.channel_activate(c, True) +# for c in channels: +# self.liquidsoapcommunicator.channel_activate(c, True) # setting init params self.liquidsoapcommunicator.playlist_push(self.liquidsoapcommunicator.config.get("install_dir") + "/configuration/blank.flac") self.liquidsoapcommunicator.set_http_url("http://stream.fro.at/fro-128.ogg") + # wait another second. lqs really starts slow.. time.sleep(1) + # set active if self.active_entry is not None: self.logger.info("LiquidSoapInitThread sets activechannel: "+str(self.active_entry)) diff --git a/modules/liquidsoap/serverfunctions.liq b/modules/liquidsoap/serverfunctions.liq index 8e3caa51af08f66a282e0063c7b6f9d94b21a728..2f4a81582222132770282965c7eaac47db1318bc 100644 --- a/modules/liquidsoap/serverfunctions.liq +++ b/modules/liquidsoap/serverfunctions.liq @@ -87,6 +87,7 @@ server.register(namespace="auraengine", end ) +# enable the seek function for the input from the filesystem server.register(namespace = source.id(input_fs), description="seek to relative position in #{source.id(input_fs)}", usage = "seek <duration in seconds>", diff --git a/modules/scheduling/calendar.py b/modules/scheduling/calendar.py index d06597f461919a635ce9d9c31ef51248edded6e5..13346c9d5b2b989ea14158476144a14c52c6eb57 100644 --- a/modules/scheduling/calendar.py +++ b/modules/scheduling/calendar.py @@ -100,24 +100,25 @@ class AuraCalendarService(threading.Thread): """ try: - # fetch upcoming schedules from ENGINE + # fetch upcoming schedules from STEERING + self.logger.debug("Fetching schedules from STEERING") self.__fetch_schedule_data__() # fetch playlist and fallbacks to the schedules from TANK + self.logger.debug("Fetching playlists from TANK") self.__fetch_schedule_entry_data__() for schedule in self.fetched_schedule_data: if "start" not in schedule: - self.logger.warning("No start of schedule given. skipping the schedule "+str(schedule)) + self.logger.warning("No start of schedule given. skipping the schedule: "+str(schedule)) continue if "end" not in schedule: - self.logger.warning("No end of schedule given. skipping the schedule "+str(schedule)) + self.logger.warning("No end of schedule given. skipping the schedule: "+str(schedule)) continue # store the schedule schedule_db = self.store_schedule(schedule) # store playlists to play - self.store_schedule_playlist(schedule_db, schedule, "playlist") self.store_schedule_playlist(schedule_db, schedule, "schedule_fallback", True) self.store_schedule_playlist(schedule_db, schedule, "show_fallback", True) @@ -125,8 +126,8 @@ class AuraCalendarService(threading.Thread): # release the mutex self.queue.put(schedule) #"fetching_finished") - except: - self.queue.put("fetching_aborted") + except Exception as e: + self.queue.put("fetching_aborted " + str(e)) # terminate the thread return @@ -151,7 +152,7 @@ class AuraCalendarService(threading.Thread): schedule_db.show_name = schedule["show_name"] schedule_db.show_hosts = schedule["show_hosts"] schedule_db.is_repetition = schedule["is_repetition"] - schedule_db.rtr_category = schedule["show_rtrcategory"] + schedule_db.funding_category = schedule["show_fundingcategory"] schedule_db.languages = schedule["show_languages"] schedule_db.type = schedule["show_type"] schedule_db.category = schedule["show_categories"] @@ -320,23 +321,59 @@ class AuraCalendarService(threading.Thread): use_testdata = False html_response = self.__fetch_data__(servicetype) - if not html_response: + if not html_response or html_response == b"[]": + self.logger.debug("Got no response: Using testdata") use_testdata = True # if an error occours => use testdata if use_testdata: - html_response = '[{"schedule_id":1,"schedule_start":"' + (datetime.now() + timedelta(hours=0)).strftime('%Y-%m-%d %H:00:00') + '","schedule_end":"' + (datetime.now() + timedelta(hours=1)).strftime('%Y-%m-%d %H:00:00') + '","show_id":9,"show_name":"FROzine","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":2,"schedule_fallback_id":12,"show_fallback_id":92,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"},{"schedule_id":2,"schedule_start":"' + (datetime.now()+timedelta(hours=1)).strftime('%Y-%m-%d %H:00:00') + '","schedule_end":"' + (datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00') + '","show_id":10,"show_name":"FROMat","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":4,"schedule_fallback_id":22,"show_fallback_id":102,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"},{"schedule_id":3,"schedule_start":"' + (datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00') + '","schedule_end":"' + (datetime.now() + timedelta(hours=3)).strftime('%Y-%m-%d %H:00:00') + '","show_id":11,"show_name":"Radio für Senioren","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":6,"schedule_fallback_id":32,"show_fallback_id":112,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"}]' + html_response = '[{"schedule_id":1,"start":"' + (datetime.now() + timedelta(hours=0)).strftime('%Y-%m-%d %H:00:00') + '","end":"' + (datetime.now() + timedelta(hours=1)).strftime('%Y-%m-%d %H:00:00') + '","show_id":9,"show_name":"FROzine","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":2,"schedule_fallback_id":12,"show_fallback_id":92,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"},{"schedule_id":2,"schedule_start":"' + (datetime.now()+timedelta(hours=1)).strftime('%Y-%m-%d %H:00:00') + '","schedule_end":"' + (datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00') + '","show_id":10,"show_name":"FROMat","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":4,"schedule_fallback_id":22,"show_fallback_id":102,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"},{"schedule_id":3,"schedule_start":"' + (datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00') + '","schedule_end":"' + (datetime.now() + timedelta(hours=3)).strftime('%Y-%m-%d %H:00:00') + '","show_id":11,"show_name":"Radio für Senioren","show_hosts":"Sandra Hochholzer, Martina Schweiger","is_repetition":false,"playlist_id":6,"schedule_fallback_id":32,"show_fallback_id":112,"station_fallback_id":1,"rtr_category":"string","comment":"Kommentar","languages":"Sprachen","type":"Typ","category":"Kategorie","topic":"Topic","musicfocus":"Fokus"}]' try: - self.fetched_schedule_data = simplejson.loads(html_response) + schedule_from_pv = simplejson.loads(html_response) except Exception as e: self.logger.critical("Cannot fetch schedule entries from PV") sys.exit() # check data self.logger.critical("Hardcoded Response && no JSON data checks. I believe what i get here") + + d = self.remove_data_more_than_24h_in_the_future(schedule_from_pv) + self.fetched_schedule_data = self.remove_data_in_the_past(d) + return self.fetched_schedule_data + # ------------------------------------------------------------------------------------------ # + def remove_data_more_than_24h_in_the_future(self, schedule_from_pv): + act_list = [] + now = datetime.now() + now_plus_24hours = now + timedelta(hours=24) + + for s in schedule_from_pv: + date_start = datetime.strptime(s["start"], "%Y-%m-%dT%H:%M:%S") + + # append only elements which are close enough to now + if date_start <= now_plus_24hours and date_start >= now - timedelta(hours=1): + act_list.append(s) + + return act_list + + # ------------------------------------------------------------------------------------------ # + def remove_data_in_the_past(self, schedule_from_pv): + act_list = [] + now = datetime.now() + + for i,curr in enumerate(schedule_from_pv[:-1]): + date_start = datetime.strptime(curr["start"], "%Y-%m-%dT%H:%M:%S") + date_next_start = datetime.strptime(schedule_from_pv[i+1]["start"], "%Y-%m-%dT%H:%M:%S") + + if date_start >= now: + act_list.append(curr) + if date_start <= now and date_next_start >= now: + act_list.append(curr) + + return act_list + # ------------------------------------------------------------------------------------------ # def __fetch_data__(self, type): # init html_response diff --git a/modules/scheduling/scheduler.py b/modules/scheduling/scheduler.py index 709e2bd00b7eee5a8fefa67c796f293cd5eec1cc..7afbff2539f75dce149d0dea7c8aded6b3728222 100644 --- a/modules/scheduling/scheduler.py +++ b/modules/scheduling/scheduler.py @@ -79,7 +79,7 @@ class AuraScheduler(ExceptionLogger, threading.Thread): config = None tried_fetching = 0 - fetch_max = 2 + fetch_max = 3 def __init__(self, config): """ @@ -358,10 +358,12 @@ class AuraScheduler(ExceptionLogger, threading.Thread): # ------------------------------------------------------------------------------------------ # def fetch_new_programme(self): + self.logger.info("trying to fetch new programme") if self.tried_fetching == self.fetch_max: - self.logger.error("Cannot connect to PV or Tank! No Programme loaded!") + msg = "Cannot connect to PV or Tank! No Programme loaded!" + self.logger.error(msg) self.tried_fetching = 0 - return "" + return msg self.tried_fetching += 1 @@ -383,8 +385,8 @@ class AuraScheduler(ExceptionLogger, threading.Thread): self.logger.critical("Programme loaded from database has no entries!") return self.get_act_programme_as_string() - elif response == "fetching_aborted": - self.logger.warning("Fetching was being aborted from AuraCalendarService! Are you connected?") + elif response.startswith("fetching_aborted"): + self.logger.warning("Fetching was being aborted from AuraCalendarService! Are you connected? Reason: " + response) else: self.logger.warning("Got an unknown response from AuraCalendarService: " + response) diff --git a/modules/web/routes.py b/modules/web/routes.py index caa731993679d9ea1978cb4b0846056c954a0b15..3cfa6aa7446d969f7355d0a6f724255c6374b203 100644 --- a/modules/web/routes.py +++ b/modules/web/routes.py @@ -14,9 +14,6 @@ from libraries.database.broadcasts import TrackService, Schedule def alchemyencoder(obj): - logger = logging.getLogger("AuraEngine") - logger.warning(str(type(obj))) - """JSON encoder function for SQLAlchemy special classes.""" if isinstance(obj, datetime.date): return obj.isoformat() @@ -36,19 +33,17 @@ class Routes: lqs_communicator = None def __init__(self, scheduler, lqs_communicator, messenger): - #self.logger = logging.getLogger("AuraEngine") - self.scheduler = scheduler self.messenger = messenger self.lqs_communicator = lqs_communicator - APP.run(debug=True) + # when debug is enabled => logging messages appear twice + APP.run() #debug=True) @staticmethod @APP.route('/') @APP.route('/index') def index(): - return "" return render_template("index.html") @staticmethod @@ -132,6 +127,8 @@ class Routes: return lqs.auraengine_state() except Exception as e: error = "Unable to fetch state from Liquidsoap. Is Soundserver running? Reason: " + str(e) + logger = logging.getLogger("AuraEngine") + logger.error(error) return simplejson.dumps({"Error": error})