Commit 1e082c76 authored by david's avatar david
Browse files

Absolute audio path config. #72

parent 80f9985f
...@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine" ...@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine"
mailsubject_prefix="[AURA Engine]" mailsubject_prefix="[AURA Engine]"
# Server where heartbeat info is sent to # Server where heartbeat info is sent to
heartbeat_server = "127.0.0.1" heartbeat_server = "127.0.0.1"
# Some UDP port # Some UDP port
heartbeat_port = 43334 heartbeat_port = 43334
# Seconds how often the vitality of the Engine should be checked (0 = disabled) # Seconds how often the vitality of the Engine should be checked (0 = disabled)
heartbeat_frequency = 0 heartbeat_frequency = 0
[api] [api]
## STEERING ## ## STEERING ##
# The URL to get the health status # The URL to get the health status
api_steering_status="http://localhost:8000/api/v1/" api_steering_status="http://localhost:8000/api/v1/"
# The URL to get the Calendar via Steering # The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout" api_steering_calendar="http://localhost:8000/api/v1/playout"
...@@ -48,7 +48,7 @@ api_steering_calendar="http://localhost:8000/api/v1/playout" ...@@ -48,7 +48,7 @@ api_steering_calendar="http://localhost:8000/api/v1/playout"
api_tank_session="engine" api_tank_session="engine"
# The secret which is used to authenticate against Tank # The secret which is used to authenticate against Tank
api_tank_secret="rather-secret" api_tank_secret="rather-secret"
# The URL to get the health status # The URL to get the health status
api_tank_status="http://localhost:8040/healthz/" api_tank_status="http://localhost:8040/healthz/"
# The URL to get playlist details via Tank # The URL to get playlist details via Tank
api_tank_playlist="http://localhost:8040/api/v1/playlists/${ID}" api_tank_playlist="http://localhost:8040/api/v1/playlists/${ID}"
...@@ -68,10 +68,10 @@ api_engine_store_health="http://localhost:8008/api/v1/source/health/${ENGINE_NUM ...@@ -68,10 +68,10 @@ api_engine_store_health="http://localhost:8008/api/v1/source/health/${ENGINE_NUM
[scheduler] [scheduler]
# Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs) # Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs)
# Either provide an absolute base path or a relative one starting in the `engine-core/src` directory. In case of `engine-core` running in docker use `/var/audio/source` # Either provide an absolute base path or a relative one starting in the `engine-core/src` directory. In case of `engine-core` running in docker use `/var/audio/source`
audio_source_folder="../audio/source" audio_source_folder="audio/source"
audio_source_extension=".flac" audio_source_extension=".flac"
# Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above) # Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above)
audio_playlist_folder="../audio/playlist" audio_playlist_folder="audio/playlist"
# Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync # Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync
engine_latency_offset=0.5 engine_latency_offset=0.5
# How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show aired # How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show aired
...@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---" ...@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---"
db_host="localhost" db_host="localhost"
db_charset="utf8" db_charset="utf8"
# The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds # The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds
# and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window. # and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window.
scheduling_window_start=60 scheduling_window_start=60
scheduling_window_end=60 scheduling_window_end=60
# How many seconds before the actual schedule time the entry should be pre-rolled. Note to provide enough timeout for # How many seconds before the actual schedule time the entry should be pre-rolled. Note to provide enough timeout for
...@@ -91,7 +91,7 @@ scheduling_window_end=60 ...@@ -91,7 +91,7 @@ scheduling_window_end=60
# the past the offset is ignored and the entry is played as soon as possible # the past the offset is ignored and the entry is played as soon as possible
preload_offset=15 preload_offset=15
# Sometimes it might take longer to get a stream connected. Here you can define a viable length. # Sometimes it might take longer to get a stream connected. Here you can define a viable length.
# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the
# overall playout, it's delays and possible fallbacks # overall playout, it's delays and possible fallbacks
input_stream_retry_delay=1 input_stream_retry_delay=1
input_stream_max_retries=10 input_stream_max_retries=10
......
...@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine" ...@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine"
mailsubject_prefix="[AURA Engine]" mailsubject_prefix="[AURA Engine]"
# Server where heartbeat info is sent to # Server where heartbeat info is sent to
heartbeat_server = "127.0.0.1" heartbeat_server = "127.0.0.1"
# Some UDP port # Some UDP port
heartbeat_port = 43334 heartbeat_port = 43334
# Seconds how often the vitality of the Engine should be checked (0 = disabled) # Seconds how often the vitality of the Engine should be checked (0 = disabled)
heartbeat_frequency = 0 heartbeat_frequency = 0
[api] [api]
## STEERING ## ## STEERING ##
# The URL to get the health status # The URL to get the health status
api_steering_status="http://aura.local:8000/api/v1/" api_steering_status="http://aura.local:8000/api/v1/"
# The URL to get the Calendar via Steering # The URL to get the Calendar via Steering
api_steering_calendar="http://aura.local:8000/api/v1/playout" api_steering_calendar="http://aura.local:8000/api/v1/playout"
...@@ -48,7 +48,7 @@ api_steering_calendar="http://aura.local:8000/api/v1/playout" ...@@ -48,7 +48,7 @@ api_steering_calendar="http://aura.local:8000/api/v1/playout"
api_tank_session="engine" api_tank_session="engine"
# The secret which is used to authenticate against Tank # The secret which is used to authenticate against Tank
api_tank_secret="rather-secret" api_tank_secret="rather-secret"
# The URL to get the health status # The URL to get the health status
api_tank_status="http://aura.local:8040/healthz/" api_tank_status="http://aura.local:8040/healthz/"
# The URL to get playlist details via Tank # The URL to get playlist details via Tank
api_tank_playlist="http://aura.local:8040/api/v1/playlists/${ID}" api_tank_playlist="http://aura.local:8040/api/v1/playlists/${ID}"
...@@ -68,10 +68,10 @@ api_engine_store_health="http://localhost:8008/api/v1/source/health/${ENGINE_NUM ...@@ -68,10 +68,10 @@ api_engine_store_health="http://localhost:8008/api/v1/source/health/${ENGINE_NUM
[scheduler] [scheduler]
# Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs) # Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs)
# Either provide an absolute base path or a relative one starting in the `engine-core/src` directory. In case of `engine-core` running in docker use `/var/audio/source` # Either provide an absolute base path or a relative one starting in the `engine-core/src` directory. In case of `engine-core` running in docker use `/var/audio/source`
audio_source_folder="../audio/source" audio_source_folder="audio/source"
audio_source_extension=".flac" audio_source_extension=".flac"
# Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above) # Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above)
audio_playlist_folder="../audio/playlist" audio_playlist_folder="audio/playlist"
# Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync # Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync
engine_latency_offset=0.5 engine_latency_offset=0.5
# How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show aired # How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show aired
...@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---" ...@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---"
db_host="localhost" db_host="localhost"
db_charset="utf8" db_charset="utf8"
# The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds # The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds
# and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window. # and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window.
scheduling_window_start=60 scheduling_window_start=60
scheduling_window_end=60 scheduling_window_end=60
# How many seconds before the actual schedule time the entry should be pre-rolled. Note to provide enough timeout for # How many seconds before the actual schedule time the entry should be pre-rolled. Note to provide enough timeout for
...@@ -91,7 +91,7 @@ scheduling_window_end=60 ...@@ -91,7 +91,7 @@ scheduling_window_end=60
# the past the offset is ignored and the entry is played as soon as possible # the past the offset is ignored and the entry is played as soon as possible
preload_offset=15 preload_offset=15
# Sometimes it might take longer to get a stream connected. Here you can define a viable length. # Sometimes it might take longer to get a stream connected. Here you can define a viable length.
# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the
# overall playout, it's delays and possible fallbacks # overall playout, it's delays and possible fallbacks
input_stream_retry_delay=1 input_stream_retry_delay=1
input_stream_max_retries=10 input_stream_max_retries=10
......
...@@ -27,9 +27,9 @@ from configparser import ConfigParser ...@@ -27,9 +27,9 @@ from configparser import ConfigParser
class AuraConfig: class AuraConfig:
""" """
AuraConfig Class AuraConfig Class
Holds the Engine Configuration as in the file `engine.ini`. Holds the Engine Configuration as in the file `engine.ini`.
""" """
instance = None instance = None
...@@ -37,7 +37,7 @@ class AuraConfig: ...@@ -37,7 +37,7 @@ class AuraConfig:
logger = None logger = None
def __init__(self, ini_path="/etc/aura/engine.ini"): def __init__(self, ini_path="/etc/aura/engine.ini"):
""" """
Initializes the configuration, defaults to `/etc/aura/engine.ini`. Initializes the configuration, defaults to `/etc/aura/engine.ini`.
If this file doesn't exist it uses `./config/engine.ini` from If this file doesn't exist it uses `./config/engine.ini` from
...@@ -46,7 +46,7 @@ class AuraConfig: ...@@ -46,7 +46,7 @@ class AuraConfig:
Args: Args:
ini_path(String): The path to the configuration file `engine.ini` ini_path(String): The path to the configuration file `engine.ini`
""" """
self.logger = logging.getLogger("AuraEngine") self.logger = logging.getLogger("AuraEngine")
config_file = Path(ini_path) config_file = Path(ini_path)
if not config_file.is_file(): if not config_file.is_file():
ini_path = "%s/config/engine.ini" % Path(__file__).parent.parent.parent.absolute() ini_path = "%s/config/engine.ini" % Path(__file__).parent.parent.parent.absolute()
...@@ -56,7 +56,7 @@ class AuraConfig: ...@@ -56,7 +56,7 @@ class AuraConfig:
AuraConfig.instance = self AuraConfig.instance = self
# Defaults # Defaults
self.set("config_dir", os.path.dirname(ini_path)) self.set("config_dir", os.path.dirname(ini_path))
self.set("install_dir", os.path.realpath(__file__ + "../../../..")) self.set("install_dir", os.path.realpath(__file__ + "../../../.."))
...@@ -152,4 +152,18 @@ class AuraConfig: ...@@ -152,4 +152,18 @@ class AuraConfig:
if path.startswith("/"): if path.startswith("/"):
return path return path
else: else:
return self.get("install_dir") + "/" + path return self.get("install_dir") + "/" + path
\ No newline at end of file
def abs_audio_store_path(self):
"""
Returns the absolute path to the audio store, based on the `audio_source_folder` setting.
"""
return self.to_abs_path(self.get("audio_source_folder"))
def abs_playlist_path(self):
"""
Returns the absolute path to the playlist folder
"""
return self.to_abs_path(self.get("audio_playlist_folder"))
...@@ -28,7 +28,7 @@ import meta ...@@ -28,7 +28,7 @@ import meta
from src.base.config import AuraConfig from src.base.config import AuraConfig
from src.base.utils import SimpleUtil as SU from src.base.utils import SimpleUtil as SU
from src.base.exceptions import LQConnectionError, InvalidChannelException, LQStreamException, LoadSourceException from src.base.exceptions import LQConnectionError, InvalidChannelException, LQStreamException, LoadSourceException
from src.resources import ResourceClass, ResourceUtil from src.resources import ResourceClass, ResourceUtil
from src.channels import ChannelType, TransitionType, LiquidsoapResponse, EntryPlayState, ResourceType, ChannelRouter from src.channels import ChannelType, TransitionType, LiquidsoapResponse, EntryPlayState, ResourceType, ChannelRouter
from src.events import EngineEventDispatcher from src.events import EngineEventDispatcher
from src.control import EngineControlInterface from src.control import EngineControlInterface
...@@ -59,13 +59,13 @@ class Engine(): ...@@ -59,13 +59,13 @@ class Engine():
Constructor Constructor
""" """
if Engine.instance: if Engine.instance:
raise Exception("Engine is already running!") raise Exception("Engine is already running!")
Engine.instance = self Engine.instance = self
self.logger = logging.getLogger("AuraEngine") self.logger = logging.getLogger("AuraEngine")
self.config = AuraConfig.config() self.config = AuraConfig.config()
Engine.engine_time_offset = float(self.config.get("engine_latency_offset")) Engine.engine_time_offset = float(self.config.get("engine_latency_offset"))
self.plugins = dict() self.plugins = dict()
self.channel_router = ChannelRouter(self.config, self.logger) self.channel_router = ChannelRouter(self.config, self.logger)
self.start() self.start()
...@@ -80,8 +80,8 @@ class Engine(): ...@@ -80,8 +80,8 @@ class Engine():
self.eci = EngineControlInterface(self, self.event_dispatcher) self.eci = EngineControlInterface(self, self.event_dispatcher)
self.connector = PlayerConnector(self.event_dispatcher) self.connector = PlayerConnector(self.event_dispatcher)
self.event_dispatcher.on_initialized() self.event_dispatcher.on_initialized()
while not self.is_connected(): while not self.is_connected():
self.logger.info(SU.yellow("Waiting for Liquidsoap to be running ...")) self.logger.info(SU.yellow("Waiting for Liquidsoap to be running ..."))
time.sleep(2) time.sleep(2)
self.logger.info(SU.green("Engine Core ------[ connected ]-------- Liquidsoap")) self.logger.info(SU.green("Engine Core ------[ connected ]-------- Liquidsoap"))
...@@ -200,7 +200,7 @@ class Player: ...@@ -200,7 +200,7 @@ class Player:
""" """
self.config = AuraConfig.config() self.config = AuraConfig.config()
self.logger = logging.getLogger("AuraEngine") self.logger = logging.getLogger("AuraEngine")
self.event_dispatcher = event_dispatcher self.event_dispatcher = event_dispatcher
self.connector = connector self.connector = connector
self.channel_router = ChannelRouter(self.config, self.logger) self.channel_router = ChannelRouter(self.config, self.logger)
self.mixer = Mixer(self.config, MixerType.MAIN, self.connector) self.mixer = Mixer(self.config, MixerType.MAIN, self.connector)
...@@ -216,8 +216,8 @@ class Player: ...@@ -216,8 +216,8 @@ class Player:
result in sitations with incorrect timing. In this case bundle multiple short entries as result in sitations with incorrect timing. In this case bundle multiple short entries as
one queue using `preload_playlist(self, entries)`. one queue using `preload_playlist(self, entries)`.
It's important to note, that his method is blocking until loading has finished. If this It's important to note, that his method is blocking until loading has finished. If this
method is called asynchronously, the progress on the preloading state can be looked up in method is called asynchronously, the progress on the preloading state can be looked up in
`entry.state`. `entry.state`.
Args: Args:
...@@ -238,7 +238,7 @@ class Player: ...@@ -238,7 +238,7 @@ class Player:
# QUEUE # QUEUE
if entry.get_content_type() in ResourceClass.FILE.types: if entry.get_content_type() in ResourceClass.FILE.types:
is_ready = self.queue_push(entry.channel, entry.source) is_ready = self.queue_push(entry.channel, entry.source)
# STREAM # STREAM
elif entry.get_content_type() in ResourceClass.STREAM.types: elif entry.get_content_type() in ResourceClass.STREAM.types:
is_ready = self.stream_load_entry(entry) is_ready = self.stream_load_entry(entry)
...@@ -252,13 +252,13 @@ class Player: ...@@ -252,13 +252,13 @@ class Player:
def preload_group(self, entries, channel_type=ChannelType.QUEUE): def preload_group(self, entries, channel_type=ChannelType.QUEUE):
""" """
Pre-Load multiple filesystem entries at once. This call is required before the Pre-Load multiple filesystem entries at once. This call is required before the
actual `play(..)` can happen. Due to their nature, non-filesystem entries cannot be queued actual `play(..)` can happen. Due to their nature, non-filesystem entries cannot be queued
using this method. In this case use `preload(self, entry)` instead. This method also allows using this method. In this case use `preload(self, entry)` instead. This method also allows
queuing of very short files, such as jingles. queuing of very short files, such as jingles.
It's important to note, that his method is blocking until loading has finished. If this It's important to note, that his method is blocking until loading has finished. If this
method is called asynchronously, the progress on the preloading state can be looked up in method is called asynchronously, the progress on the preloading state can be looked up in
`entry.state`. `entry.state`.
Args: Args:
...@@ -271,8 +271,8 @@ class Player: ...@@ -271,8 +271,8 @@ class Player:
for entry in entries: for entry in entries:
if entry.get_content_type() != ResourceType.FILE: if entry.get_content_type() != ResourceType.FILE:
raise InvalidChannelException raise InvalidChannelException
# Determine channel # Determine channel
channels = self.channel_router.channel_swap(channel_type) channels = self.channel_router.channel_swap(channel_type)
# Queue entries # Queue entries
...@@ -285,7 +285,7 @@ class Player: ...@@ -285,7 +285,7 @@ class Player:
if self.queue_push(entry.channel, entry.source) == True: if self.queue_push(entry.channel, entry.source) == True:
entry.status = EntryPlayState.READY entry.status = EntryPlayState.READY
self.event_dispatcher.on_queue(entries) self.event_dispatcher.on_queue(entries)
return channels return channels
...@@ -296,18 +296,18 @@ class Player: ...@@ -296,18 +296,18 @@ class Player:
a clean channel is selected and transitions between old and new channel is performed. a clean channel is selected and transitions between old and new channel is performed.
This method expects that the entry is pre-loaded using `preload(..)` or `preload_group(self, entries)` This method expects that the entry is pre-loaded using `preload(..)` or `preload_group(self, entries)`
before being played. In case the pre-roll has happened for a group of entries, only the before being played. In case the pre-roll has happened for a group of entries, only the
first entry of the group needs to be passed. first entry of the group needs to be passed.
Args: Args:
entry (PlaylistEntry): The audio source to be played entry (PlaylistEntry): The audio source to be played
transition (TransitionType): The type of transition to use e.g. fade-in or instant volume level. transition (TransitionType): The type of transition to use e.g. fade-in or instant volume level.
queue (Boolean): If `True` the entry is queued if the `ChannelType` does allow so; queue (Boolean): If `True` the entry is queued if the `ChannelType` does allow so;
otherwise a new channel of the same type is activated otherwise a new channel of the same type is activated
""" """
with suppress(LQConnectionError): with suppress(LQConnectionError):
channel_type = self.channel_router.type_of_channel(entry.channel) channel_type = self.channel_router.type_of_channel(entry.channel)
mixer = self.mixer mixer = self.mixer
if channel_type == ChannelType.FALLBACK_QUEUE: if channel_type == ChannelType.FALLBACK_QUEUE:
...@@ -322,7 +322,7 @@ class Player: ...@@ -322,7 +322,7 @@ class Player:
mixer.channel_activate(entry.channel.value, True) mixer.channel_activate(entry.channel.value, True)
self.connector.disable_transaction() self.connector.disable_transaction()
# Update active channel for the current channel type # Update active channel for the current channel type
self.channel_router.set_active(channel_type, entry.channel) self.channel_router.set_active(channel_type, entry.channel)
# Dear filesystem channels, please leave the room as you would like to find it! # Dear filesystem channels, please leave the room as you would like to find it!
...@@ -340,7 +340,7 @@ class Player: ...@@ -340,7 +340,7 @@ class Player:
self.logger.info("Clear Queue Response: " + res) self.logger.info("Clear Queue Response: " + res)
self.connector.disable_transaction() self.connector.disable_transaction()
Thread(target=clean_up).start() Thread(target=clean_up).start()
self.event_dispatcher.on_play(entry) self.event_dispatcher.on_play(entry)
...@@ -359,7 +359,7 @@ class Player: ...@@ -359,7 +359,7 @@ class Player:
if not entry.channel: if not entry.channel:
self.logger.warn(SU.red("Trying to stop entry %s, but it has no channel assigned" % entry)) self.logger.warn(SU.red("Trying to stop entry %s, but it has no channel assigned" % entry))
return return
if transition == TransitionType.FADE: if transition == TransitionType.FADE:
self.mixer.fade_out(entry.channel) self.mixer.fade_out(entry.channel)
else: else:
...@@ -393,7 +393,7 @@ class Player: ...@@ -393,7 +393,7 @@ class Player:
self.logger.info(f"Fading out channel '{dirty_channel}'") self.logger.info(f"Fading out channel '{dirty_channel}'")
self.connector.enable_transaction() self.connector.enable_transaction()
self.mixer_fallback.fade_out(dirty_channel) self.mixer_fallback.fade_out(dirty_channel)
self.connector.disable_transaction() self.connector.disable_transaction()
def clean_up(): def clean_up():
# Wait a little, if there is some long fade-out. Note, this also means, # Wait a little, if there is some long fade-out. Note, this also means,
...@@ -403,10 +403,10 @@ class Player: ...@@ -403,10 +403,10 @@ class Player:
self.mixer_fallback.channel_activate(dirty_channel.value, False) self.mixer_fallback.channel_activate(dirty_channel.value, False)
res = self.queue_clear(dirty_channel) res = self.queue_clear(dirty_channel)
self.logger.info("Clear Fallback Queue Response: " + res) self.logger.info("Clear Fallback Queue Response: " + res)
self.connector.disable_transaction() self.connector.disable_transaction()
self.event_dispatcher.on_fallback_cleaned(dirty_channel) self.event_dispatcher.on_fallback_cleaned(dirty_channel)
Thread(target=clean_up).start() Thread(target=clean_up).start()
# #
...@@ -427,7 +427,7 @@ class Player: ...@@ -427,7 +427,7 @@ class Player:
self.stream_load(entry.channel, entry.source) self.stream_load(entry.channel, entry.source)
time.sleep(1) time.sleep(1)
retry_delay = self.config.get("input_stream_retry_delay") retry_delay = self.config.get("input_stream_retry_delay")
max_retries = self.config.get("input_stream_max_retries") max_retries = self.config.get("input_stream_max_retries")
retries = 0 retries = 0
...@@ -458,7 +458,7 @@ class Player: ...@@ -458,7 +458,7 @@ class Player:
self.connector.enable_transaction() self.connector.enable_transaction()
result = self.connector.send_lqc_command(channel, "stream_stop") result = self.connector.send_lqc_command(channel, "stream_stop")
if result != LiquidsoapResponse.SUCCESS.value: if result != LiquidsoapResponse.SUCCESS.value:
self.logger.error("%s.stop result: %s" % (channel, result)) self.logger.error("%s.stop result: %s" % (channel, result))
raise LQStreamException("Error while stopping stream!") raise LQStreamException("Error while stopping stream!")
...@@ -517,7 +517,7 @@ class Player: ...@@ -517,7 +517,7 @@ class Player:
# #
# Channel Type - Queue # Channel Type - Queue
# #
...@@ -535,9 +535,9 @@ class Player: ...@@ -535,9 +535,9 @@ class Player:
if channel not in ChannelType.QUEUE.channels and \ if channel not in ChannelType.QUEUE.channels and \
channel not in ChannelType.FALLBACK_QUEUE.channels: channel not in ChannelType.FALLBACK_QUEUE.channels:
raise InvalidChannelException raise InvalidChannelException
self.connector.enable_transaction() self.connector.enable_transaction()
audio_store = self.config.get("audio_source_folder") audio_store = self.config.abs_audio_store_path()
extension = self.config.get("audio_source_extension") extension = self.config.get("audio_source_extension")
filepath = ResourceUtil.source_to_filepath(audio_store, source, extension) filepath = ResourceUtil.source_to_filepath(audio_store, source, extension)
self.logger.info(SU.pink(f"{channel}.queue_push('{filepath}')")) self.logger.info(SU.pink(f"{channel}.queue_push('{filepath}')"))
...@@ -607,7 +607,7 @@ class Player: ...@@ -607,7 +607,7 @@ class Player:
# #
# Channel Type - Playlist # Channel Type - Playlist
# #
...@@ -657,7 +657,7 @@ class Player: ...@@ -657,7 +657,7 @@ class Player:
class EngineSplash: class EngineSplash:
@staticmethod @staticmethod
def splash_screen(component, version): def splash_screen(component, version):
""" """
...@@ -666,11 +666,11 @@ class EngineSplash: ...@@ -666,11 +666,11 @@ class EngineSplash:
return """\n return """\n
█████╗ ██╗ ██╗██████╗ █████╗ ███████╗███╗ ██╗ ██████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗██████╗ █████╗ ███████╗███╗ ██╗ ██████╗ ██╗███╗ ██╗███████╗
██╔══██╗██║ ██║██╔══██╗██╔══██╗ ██╔════╝████╗ ██║██╔════╝ ██║████╗ ██║██╔════╝ ██╔══██╗██║ ██║██╔══██╗██╔══██╗ ██╔════╝████╗ ██║██╔════╝ ██║████╗ ██║██╔════╝
███████║██║ ██║██████╔╝███████║ █████╗ ██╔██╗ ██║██║ ███╗██║██╔██╗ ██║█████╗ ███████║██║ ██║██████╔╝███████║ █████╗ ██╔██╗ ██║██║ ███╗██║██╔██╗ ██║█████╗
██╔══██║██║ ██║██╔══██╗██╔══██║ ██╔══╝ ██║╚██╗██║██║ ██║██║██║╚██╗██║██╔══╝ ██╔══██║██║ ██║██╔══██╗██╔══██║ ██╔══╝ ██║╚██╗██║██║ ██║██║██║╚██╗██║██╔══╝
██║ ██║╚██████╔╝██║ ██║██║ ██║ ███████╗██║ ╚████║╚██████╔╝██║██║ ╚████║███████╗ ██║ ██║╚██████╔╝██║ ██║██║ ██║ ███████╗██║ ╚████║╚██████╔╝██║██║ ╚████║███████╗
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
%s v%s - Ready to play! %s v%s - Ready to play!
\n""" % (component, version) \n""" % (component, version)
...@@ -100,7 +100,7 @@ class AuraMonitor: ...@@ -100,7 +100,7 @@ class AuraMonitor:
self.heartbeat_socket = socket(AF_INET, SOCK_DGRAM) self.heartbeat_socket = socket(AF_INET, SOCK_DGRAM)
self.engine_id = self.get_engine_id() self.engine_id = self.get_engine_id()
# #
# EVENTS # EVENTS
# #
...@@ -120,7 +120,7 @@ class AuraMonitor: ...@@ -120,7 +120,7 @@ class AuraMonitor:
else: else: