Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • aura/engine
  • hermannschwaerzler/engine
  • sumpfralle/aura-engine
3 results
Show changes
%include "/home/gg/PycharmProjects/aura/modules/liquidsoap/readini.liq"
ini = read_ini("/etc/aura/aura.ini")
set("log.file",true)
set("log.file.path",list.assoc("logdir", ini)^"/<script>.log")
#set("log.file.path", "<script>.log")
set("log.file.perms",0o660)
set("log.level",3)
#fallback_audio_folder = list.assoc("fallback_audio_folder", ini)
#fallback_audio_folder = "/var/audio/fallback"
# track_sensitive => fallback_folder track sensitivity
# max_blank => maximum time of blank from source
# min_noise => minimum duration of noise on source to switch back over
# threshold => power in dB under which the stream is considered silent
#stream = fallback(track_sensitive=false,
# [ strip_blank(id="", max_blank=10., min_noise=10., threshold=0., once(input.alsa(id="sound_input", fallible=true, clock_safe=false))),
# playlist.safe(fallback_audio_folder) ])
stream = fallback(track_sensitive=false,
[ strip_blank(id="defaultstripper", max_blank=10., min_noise=10., threshold=0., single("/var/audio/fallback/music.flac")),
playlist.safe("/var/audio/fallback/NightmaresOnWax/Smokers Delight") ] )
#stream = single("/var/audio/fallback/music.flac")
output.alsa(id="player", device="hw:0,0", stream)
#output.alsa(fallible=true, input.alsa(id="sound_input", fallible=true, clock_safe=false))
#!/usr/bin/liquidsoap
%include "readini.liq"
ini = read_ini("/etc/aura/aura.ini")
#inst = if argv(1) != "" then string_of(argv(1)) else "playd" end
#instance = ref inst
%include "settings.liq"
%include "fallback.liq"
%include "serverfunctions.liq"
# create sources
input_fs = single(id="fs", "/var/audio/fallback/output.flac")
input_http = input.http(id="http", "http://stream.fro.at/fro-128.ogg")
linein_alsa_1 = input.alsa(id="linein", device="hw:0", bufferize = false)
# create fallbacks
timeslot_fallback = fallback_create(skip=true, "timeslot_fallback", create_timeslot_fallback)
station_fallback = fallback_create(skip=true, "station_fallback", create_station_fallback)
show_fallback = fallback_create(skip=true, "show_fallback", create_show_fallback)
# fill mixer
mixer = mix(id="mixer", [input_fs, input_http, linein_alsa_1])
# output source with station_fallback
output_source = fallback(track_sensitive=false, [mixer, show_fallback, timeslot_fallback, station_fallback])
# clock.unify([output_source, mixer, show_fallback, timeslot_fallback, station_fallback])
# create output
output.alsa(id="lineout", device="hw:0", bufferize = false, output_source) # mixer)
ignore(system('#{list.assoc("install_dir", ini)}/guru.py --init-player'))
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
#Create stream?
stream = list.assoc("stream", ini)
stream_type = list.assoc("stream_type", ini)
stream_bitrate = int_of_string(list.assoc("stream_bitrate", ini))
stream_port = int_of_string(list.assoc("stream_port", ini))
stream_mountpoint = list.assoc("stream_mountpoint", ini)
stream_user = list.assoc("stream_user", ini)
stream_password = list.assoc("stream_password", ini)
stream_host = list.assoc("stream_host", ini)
stream_url = list.assoc("stream_url", ini)
stream_name = list.assoc("stream_name", ini)
stream_genre = list.assoc("stream_genre", ini)
stream_description = list.assoc("stream_description", ini)
if stream != "" then
if stream_type == "icecast" then
if stream_bitrate == 24 then
ignore(output.icecast(%mp3(bitrate = 24, samplerate = 22050), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 32 then
ignore(output.icecast(%mp3(bitrate = 32, samplerate = 22050), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 48 then
ignore(output.icecast(%mp3(bitrate = 48, samplerate = 22050), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 64 then
ignore(output.icecast(%mp3(bitrate = 64, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 80 then
ignore(output.icecast(%mp3(bitrate = 80, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 96 then
ignore(output.icecast(%mp3(bitrate = 96, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 112 then
ignore(output.icecast(%mp3(bitrate = 112, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 128 then
ignore(output.icecast(%mp3(bitrate = 128, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 160 then
ignore(output.icecast(%mp3(bitrate = 160, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 192 then
ignore(output.icecast(%mp3(bitrate = 192, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 224 then
ignore(output.icecast(%mp3(bitrate = 224, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 256 then
ignore(output.icecast(%mp3(bitrate = 256, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 320 then
ignore(output.icecast(%mp3(bitrate = 320, samplerate = 44100), mount=stream_mountpoint, host=stream_host, port=stream_port, name=stream_name, url=stream_url, genre=stream_genre, description=stream_description, user=stream_user, password=stream_password, icy_metadata="true", fallible=true, s))
end
elsif stream_type == "harbor" then
if stream_bitrate == 24 then
ignore(output.harbor(%mp3(bitrate = 24, samplerate = 22050), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 32 then
ignore(output.harbor(%mp3(bitrate = 32, samplerate = 22050), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 48 then
ignore(output.harbor(%mp3(bitrate = 48, samplerate = 22050), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 64 then
ignore(output.harbor(%mp3(bitrate = 64, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 80 then
ignore(output.harbor(%mp3(bitrate = 80, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 96 then
ignore(output.harbor(%mp3(bitrate = 96, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 112 then
ignore(output.harbor(%mp3(bitrate = 112, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 128 then
ignore(output.harbor(%mp3(bitrate = 128, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 160 then
ignore(output.harbor(%mp3(bitrate = 160, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 192 then
ignore(output.harbor(%mp3(bitrate = 192, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 224 then
ignore(output.harbor(%mp3(bitrate = 224, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 256 then
ignore(output.harbor(%mp3(bitrate = 256, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
elsif stream_bitrate == 320 then
ignore(output.harbor(%mp3(bitrate = 320, samplerate = 44100), user=stream_user, password=stream_password, id="stream", port=stream_port, url=stream_url, mount=stream_mountpoint, icy_metadata="true", fallible=true, s))
end
end
end
\ No newline at end of file
set("log.file.path", "./test.log")
#input_alsa = input.alsa(bufferize=false) #, clock_safe=false)
#output.alsa(bufferize=false, input_alsa)
input_pulse = input.pulseaudio() #, clock_safe=false)
output.pulseaudio(input_pulse)
#!/usr/bin/liquidsoap
%include "/etc/aura/readini.liq"
%include "/etc/aura/library.liq"
%include "/etc/aura/playlist.liq"
inifile = '/etc/aura/aura.ini'
ini = read_ini(inifile)
socketdir = list.assoc("socketdir", ini)
# set player i/o devices
live_input_device = list.assoc("live_input_device", ini)
output_device = list.assoc("output_device", ini)
# fallback settings
station_fallback_pool = list.assoc("station_fallback_pool", ini)
ignore(station_fallback_pool)
fallback_audio_folder = list.assoc("fallback_audio_folder", ini)
fallback_max_blank = float_of_string(list.assoc("fallback_max_blank", ini))
fallback_min_noise = float_of_string(list.assoc("fallback_min_noise", ini))
fallback_threshold = float_of_string(list.assoc("fallback_threshold", ini))
# channel names from config
channelnames = ref string.split(separator=',', list.assoc("channels", ini))
set("server.socket", true)
set("server.socket.path", socketdir^"/<script>.sock")
set("server.telnet", true)
set("server.telnet.port", 1234)
# alsa settings
#set("alsa.alsa_buffer", 2048)
#set("alsa.periods", 0)
#set("alsa.buffer_length", 1)
playlistrunning = ref false
# dynamic list of sources
sources = ref []
playlist_recorded = playlist.xml(
id='playlist', on_done=fun() -> begin ignore(system('#{list.assoc("install_dir", ini)}/modules/soundengine/helpers/message.py -c #{!instance} --task=setState -n playlistcurrent -v ""')) ignore(server.execute('mixer.select 0 false')) end, 'none')
# Die Source aus der Playlist
recorded = snd(playlist_recorded)
# Skippen erlauben
add_skip_command(recorded)
# User may load a XML-Playlist
server.register(namespace='playlist',
description="Load Playlist",
usage="load <uri>",
"load",fun (p) -> begin
reload_recorded(skip=0, uri=p)
end
)
def get_station_fallback_pool()
#playlist.safe("/var/audio/fallback/NightmaresOnWax/Smokers Delight")
playlist.safe(station_fallback_pool)
#if station_fallback_pool != "" then
# print("fallbackfolder chosen: "^station_fallback_pool)
# playlist.safe(station_fallback_pool)
#else
# print("no fallbackfolder chosen. blanking 20s.")
# blank(duration=20.0)
#end
end
def get_live_input()
if live_input_device == "soundcard" then
print("autodetect input device")
#strip_blank(id="input_alsa_strip", max_blank=fallback_max_blank, min_noise=fallback_min_noise, threshold=fallback_threshold,
input.alsa(id="input_alsa", bufferize=false) #)
else
print("manually set device: "^live_input_device)
#strip_blank(id="input_alsa_strip", max_blank=fallback_max_blank, min_noise=fallback_min_noise, threshold=fallback_threshold,
input.alsa(id="input_alsa", bufferize=false, device=live_input_device) #)
end
end
def get_input_fs()
fallback(track_sensitive=false,
[ single("/var/audio/fallback/music.flac"), get_station_fallback_pool() ] )
end
def get_input_stream()
url = "http://stream.fro.at/fro128.mp3"
#url = "http://mp3stream1.apasf.apa.at:8000/listen.pls"
mksafe(strip_blank(id="stream_strip", input.http(id="stream", url)))
end
# create playlist source with smart crossfade
#filesystem_input = fallback(id="filesystem_input", track_sensitive=false, [
# get_input(),
# get_fallback()])
# filesystem_input
#fs_input = get_input_fs()
fs_input = fallback(track_sensitive=false,
[ single("/var/audio/fallback/music.flac"), get_station_fallback_pool() ] )
# create a source for stream overtakes
stream_input = get_input_stream()
#url = "http://stream.fro.at/fro64.mp3"
#url = "http://mp3stream1.apasf.apa.at:8000/listen.pls"
#stream_input = strip_blank(id="httpsttrip", input.http(id="stream", url))
# and the studio input
#live_input = get_live_input()
live_input = input.alsa(id="input_alsa", bufferize=false)
# API HOWTO:
# mixer.inputs
# stream.stop
# stream.url [url]
# stream.start
# mixer.select [streamovertake] true
def addChannel(source)
sources := list.append([source], !sources)
end
addChannel(fs_input)
addChannel(stream_input)
addChannel(live_input)
mixer = mix(id = "mixer", !sources)
#final_stream = fallback(id="station_fallback", [mixer, playlist.safe("/var/audio/fallback/NightmaresOnWax/Smokers Delight")]
#server.register(namespace='mixer',
# description="Load Playlist",
# usage="select <num>",
# "load",fun (p) -> begin
# reload_recorded(skip=0, uri=p)
# end
#)
ignore(mixer)
ignore(fs_input)
ignore(live_input)
ignore(addChannel)
ignore(stream_input)
ignore(channelnames)
ignore(output_device)
ignore(playlistrunning)
ignore(fallback_max_blank)
ignore(fallback_min_noise)
ignore(fallback_threshold)
ignore(fallback_audio_folder)
print("output_device: "^output_device)
output.alsa(id="alsaout", bufferize=false, device=output_device, mixer)
#ret = server.execute('help')
#print(ret)
# -*- coding: utf-8 -*-
#
# scheduler.py
#
# Copyright 2018 Radio FRO <https://fro.at>, Radio Helsinki <https://helsinki.at>, Radio Orange <https://o94.at>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; Version 3 of the License
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, the license can be downloaded here:
#
# http://www.gnu.org/licenses/gpl.html
# Meta
__version__ = '0.0.1'
__license__ = "GNU General Public License (GPL) Version 3"
__version_info__ = (0, 0, 1)
__author__ = 'Gottfried Gaisbauer <gottfried.gaisbauer@servus.at>'
"""
Comba Scheduler Klasse
Is holding the eventqueue
"""
import signal
import pyev
import os
import os.path
import time
import simplejson
import datetime
import decimal
import traceback
import sqlalchemy
import MySQLdb
import sys
from datetime import timedelta
from dateutil.relativedelta import relativedelta
import logging
from glob import glob
import threading
# Die eigenen Bibliotheken
from libraries.base.schedulerconfig import AuraSchedulerConfig
from modules.communication.redis.messenger import RedisMessenger
from libraries.base.calendar import AuraCalendarService
from libraries.database.broadcasts import Schedule, ScheduleEntry, AuraDatabaseModel
from libraries.exceptions.auraexceptions import NoProgrammeLoadedException
from libraries.exceptions.exception_logger import ExceptionLogger
def alchemyencoder(obj):
"""JSON encoder function for SQLAlchemy special classes."""
if isinstance(obj, datetime.date):
return obj.isoformat()
elif isinstance(obj, decimal.Decimal):
return float(obj)
elif isinstance(obj, sqlalchemy.orm.state.InstanceState):
return ""
elif isinstance(obj, Schedule):
return simplejson.dumps([obj._asdict()], default=alchemyencoder)
else:
return str(obj)
"""
Aura Scheduler Class
Gets data from pv and importer, stores and fires events,
Liefert Start und Stop Jobs an den Comba Controller, lädt XML-Playlisten und räumt auf
"""
class AuraScheduler(ExceptionLogger):
redismessenger = RedisMessenger()
liquidsoapcommunicator = None
schedule_entries = None
message_timer = []
schedulerconfig = None
job_result = {}
programme = None
client = None
debug = False
active_entry = None
def __init__(self, config):
"""
Constructor
@type config: ConfigReader
@param config: read aura.ini
"""
# Model.recreate_db(True)
self.auraconfig = config
self.debug = config.get("debug")
# Messenger für Systemzustände initieren
self.redismessenger.set_channel('scheduler')
self.redismessenger.set_section('execjob')
self.redismessenger.set_mail_addresses(self.auraconfig.get('frommail'), self.auraconfig.get('adminmail'))
self.schedulerconfig = self.auraconfig.get("scheduler_config_file")
# Die Signale, die Abbruch signalisieren
self.stopsignals = (signal.SIGTERM, signal.SIGINT)
# das pyev Loop-Object
self.loop = pyev.default_loop()
# Das ist kein Reload
self.initial = True
# Der Scheduler wartet noch auf den Start Befehl
self.ready = False
# Die Config laden
# self.__load_config__()
self.scriptdir = os.path.dirname(os.path.abspath(__file__)) + '/..'
#errors_file = os.path.dirname(os.path.realpath(__file__)) + '/error/scheduler_error.js'
json_data = open(self.auraconfig.get("install_dir") + "/errormessages/scheduler_error.js")
self.errorData = simplejson.load(json_data)
# init database ?
self.init_database()
self.redismessenger.send('Scheduler started', '0000', 'success', 'initApp', None, 'appinternal')
# ------------------------------------------------------------------------------------------ #
def init_database(self):
# check if tables do exist. if not create them
try:
ScheduleEntry.select_all()
except sqlalchemy.exc.ProgrammingError as e:
if e.__dict__["code"] == "f405":
AuraDatabaseModel.recreate_db()
else:
raise
# ------------------------------------------------------------------------------------------ #
# def set(self, key, value):
# """
# Eine property setzen
# @type key: string
# @param key: Der Key
# @type value: mixed
# @param value: Beliebiger Wert
# """
# self.__dict__[key] = value
# ------------------------------------------------------------------------------------------ #
# def get(self, key, default=None):
# """
# Eine property holen
# @type key: string
# @param key: Der Key
# @type default: mixed
# @param default: Beliebiger Wert#
#
# """
# if key not in self.__dict__:
# if default:
# self.set(key, default)
# else:
# return None
# return self.__dict__[key]
# ------------------------------------------------------------------------------------------ #
def reload_config(self):
"""
Reload Scheduler - Config neu einlesen
"""
self.stop()
# Scheduler Config neu laden
if self.__load_config__():
self.redismessenger.send('Scheduler reloaded by user', '0500', 'success', 'reload', None, 'appinternal')
self.start()
# ------------------------------------------------------------------------------------------ #
def get_active_source(self):
now_unix = time.mktime(datetime.datetime.now().timetuple())
actsource = ""
lastentry = None
# load programme if necessary
if self.programme is None:
print("want to get active channel, but have to load programme first")
self.load_programme_from_db()
# get active source
for entry in self.programme:
# check if lastentry is set and if act entry is in the future
if lastentry is not None and entry.entry_start_unix > now_unix:
# return lastentry if so
actsource = entry.source
break
lastentry = entry
if actsource.startswith("file") or actsource.startswith("pool") or actsource.startswith("playlist"):
print("AuraScheduler found upcoming source '" + str(entry.__dict__) + "'! returning: fs")
return "fs"
elif actsource.startswith("http"):
print("AuraScheduler found upcoming source '" + str(entry.__dict__) + "'! returning: http")
return "http"
elif actsource.startswith("linein"):
print("AuraScheduler found upcoming source '" + str(entry.__dict__) + "'! returning: linein")
return "linein"
return ""
# ------------------------------------------------------------------------------------------ #
def load_programme_from_db(self, silent=False):
self.programme = ScheduleEntry.select_all()
if not silent:
print("i am the scheduler and i am holding the following stuff")
# now in unixtime
now_unix = time.mktime(datetime.datetime.now().timetuple())
# switch to check if its the first stream in loaded programme
first_stream_in_programme = False
for entry in self.programme:
# since we get also programmes from act hour, filter these out
if entry.entry_start_unix > now_unix:
# when do we have to start?
diff = entry.entry_start_unix - now_unix
diff = diff/100 # testing purpose
# create the activation threads and run them after <diff> seconds
if entry.source.startswith("linein"):
self.add_or_update_timer(entry, diff, self.liquidsoapcommunicator.activate, "linein")
elif entry.source.startswith("http"):
if first_stream_in_programme:
self.liquidsoapcommunicator.next_stream_source(entry.source)
first_stream_in_programme = False
self.add_or_update_timer(entry, diff, self.liquidsoapcommunicator.activate, "http")
elif entry.source.startswith("file"):
self.add_or_update_timer(entry, diff, self.liquidsoapcommunicator.activate, "fs")
else:
print("WARNING: Cannot understand source '" + entry.source + "' from " + str(entry.__dict__))
print(" Not setting any activation Thread!")
if not silent:
print(entry.__dict__)
# ------------------------------------------------------------------------------------------ #
def add_or_update_timer(self, entry, diff, func, type):
# check if something is planned at given time
planned_timer = self.is_something_planned_at_time(entry.entry_start)
# if something is planned on entry.entry_start
if planned_timer:
planned_entry = planned_timer.entry
# check if the playlist_id's are different
if planned_entry.playlist_id != entry.playlist_id:
# if not stop the old timer and remove it from the list
self.stop_timer(planned_timer)
# and create a new one
self.create_timer(entry, diff, func, type)
# if the playlist id's do not differ => do nothing, they are the same
# if nothing is planned at given time, create a new timer
else:
self.create_timer(entry, diff, func, type)
# ------------------------------------------------------------------------------------------ #
def stop_timer(self, timer):
# stop timer
timer.cancel()
# and remove it from message queue
self.message_timer.remove(timer)
# ------------------------------------------------------------------------------------------ #
def create_timer(self, entry, diff, func, type):
t = MessageTimer(diff, func, [entry, type], self.debug)
self.message_timer.append(t)
t.start()
# ------------------------------------------------------------------------------------------ #
def is_something_planned_at_time(self, given_time):
for t in self.message_timer:
if t.entry.entry_start == given_time:
return t
return False
# ------------------------------------------------------------------------------------------ #
def find_entry_in_timers(self, entry):
# check if a playlist id is already planned
for t in self.message_timer:
if t.entry.playlist_id == entry.playlist_id and t.entry.entry_start == entry.entry_start:
return t
return False
# ------------------------------------------------------------------------------------------ #
def get_act_programme_as_string(self):
programme_as_string = ""
if self.programme is None:
raise NoProgrammeLoadedException("")
try:
programme_as_string = simplejson.dumps([p._asdict() for p in self.programme], default=alchemyencoder)
except:
traceback.print_exc()
return programme_as_string
# ------------------------------------------------------------------------------------------ #
def print_message_queue(self):
message_queue = ""
for t in self.message_timer:
message_queue += t.get_info()+"\n"
return message_queue
# ------------------------------------------------------------------------------------------ #
# ------------------------------------------------------------------------------------------ #
def swap_playlist_entries(self, indexes):
from_entry = None
to_entry = None
from_idx = indexes["from_index"]
to_idx = indexes["to_index"]
# find the entries
for p in self.programme:
if p.programme_index == int(from_idx):
from_entry = p
if p.programme_index == int(to_idx):
to_entry = p
# break out of loop, if both entries found
if from_entry is not None and to_entry is not None:
break
# check if entries are found
if from_entry is None or to_entry is None:
return "From or To Entry not found!"
# swap sources
swap_source = from_entry.source
from_entry.source = to_entry.source
to_entry.source = swap_source
# store to database
from_entry.store(add=False, commit=False)
to_entry.store(add=False, commit=True)
# and return the programme with swapped entries
return self.get_act_programme_as_string()
# ------------------------------------------------------------------------------------------ #
def delete_playlist_entry(self, index):
found = False
for p in self.programme:
if p.programme_index == int(index):
p.delete(True)
self.load_programme_from_db()
found = True
break
if not found:
print("WARNING: Nothing to delete")
return self.get_act_programme_as_string()
# ------------------------------------------------------------------------------------------ #
def insert_playlist_entry(self, fromtime_source):
fromtime = fromtime_source["fromtime"]
source = fromtime_source["source"]
entry = ScheduleEntry()
entry.entry_start = fromtime
entry.source = source
entry.playlist_id = 0
entry.schedule_id = 0
entry.entry_num = ScheduleEntry.select_next_manual_entry_num()
entry.store(add=True, commit=True)
self.load_programme_from_db()
return self.get_act_programme_as_string()
# ------------------------------------------------------------------------------------------ #
def __load_config__(self):
"""
Scheduler-Config importieren
@rtype: boolean
@return: True/False
"""
# Wenn das Scheduling bereits läuft, muss der Scheduler nicht unbedingt angehalten werden
error_type = 'fatal' if self.initial else 'error'
# watcher_jobs = self.getJobs()
try:
# Die Jobs aus der Config ...
watcher_jobs = self.get_jobs()
except:
self.redismessenger.send('Config is broken', '0301', error_type, 'loadConfig', None, 'config')
if self.initial:
self.ready = False
return False
# Fehlermeldung senden, wenn keine Jobs gefunden worden sind
if len(watcher_jobs) == 0:
self.redismessenger.send('No Jobs found in Config', '0302', error_type, 'loadConfig', None, 'config')
return True
def get_jobs(self):
error_type = 'fatal' if self.initial else 'error'
try:
# Das scheduler.xml laden
self.schedulerconfig = AuraSchedulerConfig(self.schedulerconfig)
except:
# Das scheint kein gültiges XML zu sein
self.redismessenger.send('Config is broken', '0301', error_type, 'loadConfig', None, 'config')
# Wenn das beim Start passiert können wir nix tun
if self.initial:
self.ready = False
return False
jobs = self.schedulerconfig.getJobs()
for job in jobs:
if job['job'] == 'start_recording' or job['job'] == 'play_playlist':
stopjob = self.__get_stop_job__(job)
jobs.append(stopjob)
return jobs
# -----------------------------------------------------------------------#
def __get_stop_job__(self, startjob):
job = {}
job['job'] = 'stop_playlist' if startjob['job'] == 'play_playlist' else 'stop_recording'
if startjob['day'] == 'all':
job['day'] = startjob['day']
else:
if startjob['time'] < startjob['until']:
job['day'] = startjob['day']
else:
try:
day = int(startjob['day'])
stopday = 0 if day > 5 else day+1
job['day'] = str(stopday)
except:
job['day'] = 'all'
job['time'] = startjob['until']
return job
# ------------------------------------------------------------------------------------------ #
def start(self):
"""
Event Loop starten
"""
# Alle watcher starten
for watcher in self.watchers:
watcher.start()
logging.debug("{0}: started".format(self))
try:
self.loop.start()
except:
self.redismessenger.send("Loop did'nt start", '0302', 'fatal', 'appstart', None, 'appinternal')
else:
self.redismessenger.send("Scheduler started", '0100', 'success', 'appstart', None, 'appinternal')
# ------------------------------------------------------------------------------------------ #
def stop(self):
"""
Event Loop stoppen
"""
self.loop.stop(pyev.EVBREAK_ALL)
# alle watchers stoppen und entfernen
while self.watchers:
self.watchers.pop().stop()
self.redismessenger.send("Loop stopped", '0400', 'success', 'appstart', None, 'appinternal')
# ------------------------------------------------------------------------------------------ #
def signal_cb(self, loop, revents):
"""
Signalverarbeitung bei Abbruch
@type loop: object
@param loop: Das py_ev loop Objekt
@type revents: object
@param revents: Event Callbacks
"""
self.redismessenger.send("Received stop signal", '1100', 'success', 'appstop', None, 'appinternal')
self.stop()
# ------------------------------------------------------------------------------------------ #
def signal_reload(self, loop, revents):
"""
Lädt Scheduling-Konfiguration neu bei Signal SIGUSR1
@type loop: object
@param loop: Das py_ev loop Objekt
@type revents: object
@param revents: Event Callbacks
"""
self.redismessenger.send("Comba Scheduler gracefully restarted", '1200', 'success', 'appreload', None, 'appinternal')
self.reload_config()
# ------------------------------------------------------------------------------------------ #
def load_playlist(self, data=None):
"""
Playlist laden
"""
store = AuraCalendarService()
uri = store.get_uri()
store.start()
# wait until childs thread returns
store.join()
data = {}
data['uri'] = uri
result = self.client.playlist_load(uri)
if self.__check_result__(result):
self.success('load_playlist', data, '00')
else:
self.error('load_playlist', data, '02')
# ------------------------------------------------------------------------------------------ #
def start_recording(self, data):
"""
Aufnahme starten
"""
result = self.client.recorder_start()
# store = AuraCalendarService()
# self._preparePlaylistStore(store, datetime.datetime.now(), data)
# uri = store.getUri()
# store.start()
if self.__check_result__(result):
self.success('start_recording', result, '00')
else:
self.error('start_recording', result, '01')
# ------------------------------------------------------------------------------------------ #
def stop_recording(self, data):
"""
Aufnahme anhalten
"""
result = self.client.recorder_stop()
if self.__check_result__(result):
self.success('stop_recording', result, '00')
else:
self.error('stop_recording', result, '01')
class MessageTimer(threading.Timer):
entry = None
debug = False
diff = None
def __init__(self, diff, func, param, debug=True):
threading.Timer.__init__(self, diff, func, param)
self.diff = diff
self.func = func
self.entry = param[0]
self.debug = debug
self.get_info()
def get_info(self):
if self.debug:
print("MessageTimer starting @ " + str(self.entry.entry_start) + " source '" + str(self.entry.source) + "' In seconds: " + str(self.diff))
return "Calling " + str(self.func) + " @ " + str(self.entry.entry_start)
import simplejson
from libraries.enum.redischannels import Channels
from modules.communication.redis.adapter import ClientRedisAdapter, ServerRedisAdapter
class Padavan:
args = None
config = None
lsc = None
zmqclient = None
redisclient = None
stringreply = ""
# ------------------------------------------------------------------------------------------ #
def __init__(self, args, config):
self.args = args
self.config = config
# ------------------------------------------------------------------------------------------ #
def meditate(self):
if self.args.fetch_new_programme:
self.fetch_new_programme()
elif self.args.get_active_mixer:
self.get_active_mixer()
elif self.args.get_mixer_status:
self.get_mixer_status()
elif self.args.get_act_programme:
self.get_act_programme()
# elif self.args.add_source:
# print("Guru still has to learn to add a source")
elif self.args.redis_message:
self.redis_message(self.args.redis_message[0], self.args.redis_message[1])
elif self.args.select_mixer != -1:
self.select_mixer(self.args.select_mixer)
elif self.args.deselect_mixer != -1:
self.select_mixer(self.args.deselect_mixer, False)
elif self.args.set_volume:
self.set_volume(self.args.set_volume[0], self.args.set_volume[1])
elif self.args.swap_playlist_entries:
self.swap_playlist_entries(self.args.swap_playlist_entries[0], self.args.swap_playlist_entries[1])
elif self.args.delete_playlist_entry:
self.delete_playlist_entry(self.args.delete_playlist_entry)
elif self.args.insert_playlist_entry:
self.insert_playlist_entry(self.args.insert_playlist_entry[0], self.args.insert_playlist_entry[1]) #, self.args.insert_playlist_entry[2])
elif self.args.print_message_queue:
self.print_message_queue()
elif self.args.get_fallback_for:
self.get_next_fallback_file(self.args.get_fallback_for)
elif self.args.set_fallback_for:
self.set_next_fallback_file(self.args.set_fallback_for[0], self.args.set_fallback_for[1])
elif self.args.init_player:
self.init_player()
# else:
# raise Exception("")
# init liquid => faster exec time, when loading at runtime just what is needed
def init_liquidsoap_communication(self):
# import
from modules.communication.liquidsoap.communicator import LiquidSoapCommunicator
# init liquidsoap communication
self.lsc = LiquidSoapCommunicator(self.config)
# init zmq => faster exec time, when loading at runtime just what is needed
# surgically removed => should not be needed anymore
def init_zmq_communication(self):
# import
from modules.communication.zmq.adapter import ClientZMQAdapter
# and init
self.zmqclient = ClientZMQAdapter(self.config.get('zmqhostip'), self.config.get('zmqport'), debug=False)
def init_redis_communication(self, with_server=False):
self.redisclient = ClientRedisAdapter()
if with_server:
self.redisserver = ServerRedisAdapter()
def send_redis(self, channel, message):
self.init_redis_communication()
self.redisclient.publish(channel, message)
def send_and_wait_redis(self, channel, message, reply_channel):
self.init_redis_communication(True)
self.redisclient.publish(channel, message)
reply = self.redisserver.listen_for_one_message(reply_channel.value)
return reply
def fetch_new_programme(self):
json_reply = self.send_and_wait_redis("aura", "fetch_new_programme", Channels.FNP_REPLY)
actprogramme = simplejson.loads(json_reply)
self.print_programme(actprogramme)
def get_act_programme(self):
json_reply = self.send_and_wait_redis("aura", "get_act_programme", Channels.GAP_REPLY)
actprogramme = simplejson.loads(json_reply)
self.print_programme(actprogramme)
def print_programme(self, programme):
for entry in programme:
#print(entry)
#self.stringreply += entry._asdict()
self.stringreply += "idx: " + str(entry["programme_index"]) + \
" --- schedule id #" + str(entry["schedule_id"]) + "." + str(entry["entry_num"]) + \
" - show: " + entry["schedule"]["show_name"] + \
" - starts @ " + entry["entry_start"] + \
" - plays " + str(entry["source"]) + "\n"
# " ending @ " + entry["entry_end"] + \
def init_player(self):
self.stringreply = self.send_and_wait_redis("aura", "init_player", Channels.IP_REPLY)
def redis_message(self, channel, message):
self.send_redis(channel, message)
self.stringreply = "Message '"+message+"' sent to channel '"+channel+"'"
def swap_playlist_entries(self, from_index, to_index):
json_reply = self.send_and_wait_redis("aura", "swap_playlist_entries " + str(from_index) + " " + str(to_index), Channels.MPE_REPLY)
actprogramme = simplejson.loads(json_reply)
self.print_programme(actprogramme)
def delete_playlist_entry(self, index):
json_reply = self.send_and_wait_redis("aura", "delete_playlist_entry " + str(index), Channels.DPE_REPLY)
actprogramme = simplejson.loads(json_reply)
self.print_programme(actprogramme)
def insert_playlist_entry(self, fromtime, source):
json_reply = self.send_and_wait_redis("aura", "insert_playlist_entry " + fromtime + " " + source, Channels.IPE_REPLY)
actprogramme = simplejson.loads(json_reply)
self.print_programme(actprogramme)
def print_message_queue(self):
self.stringreply = self.send_and_wait_redis("aura", "print_message_queue", Channels.PMQ_REPLY)
# LIQUIDSOAP #
def select_mixer(self, mixernumber, activate=True):
self.init_liquidsoap_communication()
# select mixer and return the feedback
self.stringreply = self.lsc.channel_activate(mixernumber, activate)
def set_volume(self, mixernumber, volume):
self.init_liquidsoap_communication()
self.stringreply = self.lsc.set_volume(mixernumber, volume)
def get_active_mixer(self):
self.init_liquidsoap_communication()
am = self.lsc.get_active_mixer()
if len(am) == 0:
raise Exception("Guru recognized a problem: No active source!!!")
self.stringreply = str(am)
def get_mixer_status(self):
self.init_liquidsoap_communication()
status = self.lsc.get_mixer_status()
for k, v in status.items():
self.stringreply += "source: " + k + "\t status: " + v + "\n"
# REDIS #
def get_next_fallback_file(self, type):
from modules.communication.redis.messenger import RedisMessenger
redis = RedisMessenger()
next_fallback_file = redis.get_next_file_for_fallback(type)
#"annotate:file_id='3541',length='400.0',title='Titel',artist='Artist',album='Album',canal='reggae':" +
self.stringreply = next_fallback_file
def set_next_fallback_file(self, type, file):
from modules.communication.redis.messenger import RedisMessenger
redis = RedisMessenger()
redis.set_next_file_for_fallback(type, file)
self.stringreply = "Set "+file+" for fallback '"+type+"'"
from libraries.database.database import app, db
class Routes:
def __init__(self):
app.run()
@staticmethod
@app.route('/')
@app.route('/index')
def index():
return "Welcome to Aura. Please use the CLI Tool guru.py to manipulate the server. Web service is in planned..."
@staticmethod
@app.route("/trackservice", methods=["GET"])
def trackservice():
return "trackservice is on the way"
\ No newline at end of file
#!/usr/bin/python3
from libraries.database.broadcasts import *
import simplejson
import sqlalchemy
def alchemyencoder(obj):
"""JSON encoder function for SQLAlchemy special classes."""
if isinstance(obj, datetime.date):
return obj.isoformat()
elif isinstance(obj, decimal.Decimal):
return float(obj)
elif isinstance(obj, sqlalchemy.orm.state.InstanceState):
return ""
#elif isinstance(obj, Schedule):
# return simplejson.dumps([obj._asdict()], default=alchemyencoder)
else:
return str(obj)
def select_with_relationship():
se = TrackServiceScheduleEntry.select_all()
print(se)
# programme_as_string = simplejson.dumps([se[0]._asdict()], default=alchemyencoder)
# print(programme_as_string)
# # ## ## ## ## ## # #
# # ENTRY FUNCTION # #
# # ## ## ## ## ## # #
def main():
select_with_relationship()
# # ## ## ## ## ## ## # #
# # End ENTRY FUNCTION # #
# # ## ## ## ## ## ## # #
if __name__ == "__main__":
main()