diff --git a/config/sample-development.engine.ini b/config/sample-development.engine.ini
index c8496bad2eee3c1ba76496f5f559d53733598182..9633492fcf2aad4ef3da4ae0e5d2543c2498ecb4 100644
--- a/config/sample-development.engine.ini
+++ b/config/sample-development.engine.ini
@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine"
 mailsubject_prefix="[AURA Engine]"
 
 # Server where heartbeat info is sent to
-heartbeat_server = "127.0.0.1"   
+heartbeat_server = "127.0.0.1"
 # Some UDP port
-heartbeat_port = 43334 
+heartbeat_port = 43334
 # Seconds how often the vitality of the Engine should be checked (0 = disabled)
 heartbeat_frequency = 0
 
 [api]
 ## STEERING ##
-# The URL to get the health status 
+# The URL to get the health status
 api_steering_status="http://localhost:8000/api/v1/"
 # The URL to get the Calendar via Steering
 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"
 # The secret which is used to authenticate against Tank
 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/"
 # The URL to get playlist details via Tank
 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
 [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)
 # 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"
 # 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
 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
@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---"
 db_host="localhost"
 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
-# 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_end=60
 # 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
 # the past the offset is ignored and the entry is played as soon as possible
 preload_offset=15
 # 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
 input_stream_retry_delay=1
 input_stream_max_retries=10
diff --git a/config/sample-production.engine.ini b/config/sample-production.engine.ini
index 8a66740180a0af155a0d028088d4b8287e34ef2c..718ca0446636b6006feff74ea1cdf626395841b0 100644
--- a/config/sample-production.engine.ini
+++ b/config/sample-production.engine.ini
@@ -30,15 +30,15 @@ from_mail="monitoring@aura.engine"
 mailsubject_prefix="[AURA Engine]"
 
 # Server where heartbeat info is sent to
-heartbeat_server = "127.0.0.1"   
+heartbeat_server = "127.0.0.1"
 # Some UDP port
-heartbeat_port = 43334 
+heartbeat_port = 43334
 # Seconds how often the vitality of the Engine should be checked (0 = disabled)
 heartbeat_frequency = 0
 
 [api]
 ## STEERING ##
-# The URL to get the health status 
+# The URL to get the health status
 api_steering_status="http://aura.local:8000/api/v1/"
 # The URL to get the Calendar via Steering
 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"
 # The secret which is used to authenticate against Tank
 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/"
 # The URL to get playlist details via Tank
 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
 [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)
 # 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"
 # 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
 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
@@ -83,7 +83,7 @@ db_pass="---SECRET--PASSWORD---"
 db_host="localhost"
 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
-# 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_end=60
 # 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
 # the past the offset is ignored and the entry is played as soon as possible
 preload_offset=15
 # 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
 input_stream_retry_delay=1
 input_stream_max_retries=10
diff --git a/src/base/config.py b/src/base/config.py
index 14ec5103cd61362f4c61a7d4b9d9bda780cb9ba7..1d4679ba11cd03912e9c782a1921b40c0a98db7b 100644
--- a/src/base/config.py
+++ b/src/base/config.py
@@ -27,9 +27,9 @@ from configparser import ConfigParser
 
 
 class AuraConfig:
-    """ 
+    """
     AuraConfig Class
-    
+
     Holds the Engine Configuration as in the file `engine.ini`.
     """
     instance = None
@@ -37,7 +37,7 @@ class AuraConfig:
     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`.
         If this file doesn't exist it uses `./config/engine.ini` from
@@ -46,7 +46,7 @@ class AuraConfig:
         Args:
             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)
         if not config_file.is_file():
             ini_path = "%s/config/engine.ini" % Path(__file__).parent.parent.parent.absolute()
@@ -56,7 +56,7 @@ class AuraConfig:
         AuraConfig.instance = self
 
         # 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__ + "../../../.."))
 
 
@@ -152,4 +152,18 @@ class AuraConfig:
         if path.startswith("/"):
             return path
         else:
-            return self.get("install_dir") + "/" + path
\ No newline at end of file
+            return self.get("install_dir") + "/" + path
+
+
+    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"))
diff --git a/src/engine.py b/src/engine.py
index d0829c7b0273b6f3c87e1c58741aab4984ed9510..07e5e9ebe2f761bf669ca9251185b91c71b4be38 100644
--- a/src/engine.py
+++ b/src/engine.py
@@ -28,7 +28,7 @@ import meta
 from src.base.config        import AuraConfig
 from src.base.utils         import SimpleUtil as SU
 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.events             import EngineEventDispatcher
 from src.control            import EngineControlInterface
@@ -59,13 +59,13 @@ class Engine():
         Constructor
         """
         if Engine.instance:
-            raise Exception("Engine is already running!")        
-        Engine.instance = self         
-        self.logger = logging.getLogger("AuraEngine")            
+            raise Exception("Engine is already running!")
+        Engine.instance = self
+        self.logger = logging.getLogger("AuraEngine")
         self.config = AuraConfig.config()
         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.start()
 
@@ -80,8 +80,8 @@ class Engine():
         self.eci = EngineControlInterface(self, self.event_dispatcher)
         self.connector = PlayerConnector(self.event_dispatcher)
         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 ..."))
             time.sleep(2)
         self.logger.info(SU.green("Engine Core ------[ connected ]-------- Liquidsoap"))
@@ -200,7 +200,7 @@ class Player:
         """
         self.config = AuraConfig.config()
         self.logger = logging.getLogger("AuraEngine")
-        self.event_dispatcher = event_dispatcher        
+        self.event_dispatcher = event_dispatcher
         self.connector = connector
         self.channel_router = ChannelRouter(self.config, self.logger)
         self.mixer = Mixer(self.config, MixerType.MAIN, self.connector)
@@ -216,8 +216,8 @@ class Player:
         result in sitations with incorrect timing. In this case bundle multiple short entries as
         one queue using `preload_playlist(self, entries)`.
 
-        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 
+        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
         `entry.state`.
 
         Args:
@@ -238,7 +238,7 @@ class Player:
         # QUEUE
         if entry.get_content_type() in ResourceClass.FILE.types:
             is_ready = self.queue_push(entry.channel, entry.source)
-            
+
         # STREAM
         elif entry.get_content_type() in ResourceClass.STREAM.types:
             is_ready = self.stream_load_entry(entry)
@@ -252,13 +252,13 @@ class Player:
 
     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
         using this method. In this case use `preload(self, entry)` instead. This method also allows
         queuing of very short files, such as jingles.
 
-        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 
+        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
         `entry.state`.
 
         Args:
@@ -271,8 +271,8 @@ class Player:
         for entry in entries:
             if entry.get_content_type() != ResourceType.FILE:
                 raise InvalidChannelException
-        
-        # Determine channel        
+
+        # Determine channel
         channels = self.channel_router.channel_swap(channel_type)
 
         # Queue entries
@@ -285,7 +285,7 @@ class Player:
 
             if self.queue_push(entry.channel, entry.source) == True:
                 entry.status = EntryPlayState.READY
-        
+
         self.event_dispatcher.on_queue(entries)
         return channels
 
@@ -296,18 +296,18 @@ class Player:
         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)`
-        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.
 
         Args:
             entry (PlaylistEntry):          The audio source to be played
             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
-        
+
         """
         with suppress(LQConnectionError):
-            
+
             channel_type = self.channel_router.type_of_channel(entry.channel)
             mixer = self.mixer
             if channel_type == ChannelType.FALLBACK_QUEUE:
@@ -322,7 +322,7 @@ class Player:
                 mixer.channel_activate(entry.channel.value, True)
             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)
 
             # Dear filesystem channels, please leave the room as you would like to find it!
@@ -340,7 +340,7 @@ class Player:
                     self.logger.info("Clear Queue Response: " + res)
                     self.connector.disable_transaction()
                 Thread(target=clean_up).start()
-            
+
             self.event_dispatcher.on_play(entry)
 
 
@@ -359,7 +359,7 @@ class Player:
             if not entry.channel:
                 self.logger.warn(SU.red("Trying to stop entry %s, but it has no channel assigned" % entry))
                 return
-            
+
             if transition == TransitionType.FADE:
                 self.mixer.fade_out(entry.channel)
             else:
@@ -393,7 +393,7 @@ class Player:
         self.logger.info(f"Fading out channel '{dirty_channel}'")
         self.connector.enable_transaction()
         self.mixer_fallback.fade_out(dirty_channel)
-        self.connector.disable_transaction()  
+        self.connector.disable_transaction()
 
         def clean_up():
             # Wait a little, if there is some long fade-out. Note, this also means,
@@ -403,10 +403,10 @@ class Player:
             self.mixer_fallback.channel_activate(dirty_channel.value, False)
             res = self.queue_clear(dirty_channel)
             self.logger.info("Clear Fallback Queue Response: " + res)
-            self.connector.disable_transaction()            
+            self.connector.disable_transaction()
             self.event_dispatcher.on_fallback_cleaned(dirty_channel)
         Thread(target=clean_up).start()
-        
+
 
 
     #
@@ -427,7 +427,7 @@ class Player:
         self.stream_load(entry.channel, entry.source)
         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")
         retries = 0
 
@@ -458,7 +458,7 @@ class Player:
 
         self.connector.enable_transaction()
         result = self.connector.send_lqc_command(channel, "stream_stop")
-        
+
         if result != LiquidsoapResponse.SUCCESS.value:
             self.logger.error("%s.stop result: %s" % (channel, result))
             raise LQStreamException("Error while stopping stream!")
@@ -517,7 +517,7 @@ class Player:
 
 
     #
-    #   Channel Type - Queue 
+    #   Channel Type - Queue
     #
 
 
@@ -535,9 +535,9 @@ class Player:
         if channel not in ChannelType.QUEUE.channels and \
             channel not in ChannelType.FALLBACK_QUEUE.channels:
                 raise InvalidChannelException
-      
+
         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")
         filepath = ResourceUtil.source_to_filepath(audio_store, source, extension)
         self.logger.info(SU.pink(f"{channel}.queue_push('{filepath}')"))
@@ -607,7 +607,7 @@ class Player:
 
 
     #
-    #   Channel Type - Playlist 
+    #   Channel Type - Playlist
     #
 
 
@@ -657,7 +657,7 @@ class Player:
 
 
 class EngineSplash:
-    
+
     @staticmethod
     def splash_screen(component, version):
         """
@@ -666,11 +666,11 @@ class EngineSplash:
         return """\n
              █████╗ ██╗   ██╗██████╗  █████╗     ███████╗███╗   ██╗ ██████╗ ██╗███╗   ██╗███████╗
             ██╔══██╗██║   ██║██╔══██╗██╔══██╗    ██╔════╝████╗  ██║██╔════╝ ██║████╗  ██║██╔════╝
-            ███████║██║   ██║██████╔╝███████║    █████╗  ██╔██╗ ██║██║  ███╗██║██╔██╗ ██║█████╗  
-            ██╔══██║██║   ██║██╔══██╗██╔══██║    ██╔══╝  ██║╚██╗██║██║   ██║██║██║╚██╗██║██╔══╝  
+            ███████║██║   ██║██████╔╝███████║    █████╗  ██╔██╗ ██║██║  ███╗██║██╔██╗ ██║█████╗
+            ██╔══██║██║   ██║██╔══██╗██╔══██║    ██╔══╝  ██║╚██╗██║██║   ██║██║██║╚██╗██║██╔══╝
             ██║  ██║╚██████╔╝██║  ██║██║  ██║    ███████╗██║ ╚████║╚██████╔╝██║██║ ╚████║███████╗
             ╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝    ╚══════╝╚═╝  ╚═══╝ ╚═════╝ ╚═╝╚═╝  ╚═══╝╚══════╝
             %s v%s - Ready to play!
-        \n""" % (component, version)       
+        \n""" % (component, version)
 
 
diff --git a/src/plugins/monitor.py b/src/plugins/monitor.py
index 5c5bf769e49796549563a8682c91e4c5a9de3b88..3ae57fbf71865499f1f6c1571a6dc9307787b0d2 100644
--- a/src/plugins/monitor.py
+++ b/src/plugins/monitor.py
@@ -100,7 +100,7 @@ class AuraMonitor:
         self.heartbeat_socket = socket(AF_INET, SOCK_DGRAM)
 
         self.engine_id = self.get_engine_id()
-    
+
     #
     # EVENTS
     #
@@ -120,7 +120,7 @@ class AuraMonitor:
         else:
             self.logger.info("Engine Status: " + SU.green("[OK]"))
             self.post_health(status, True)
-        
+
 
 
     def on_sick(self, data):
@@ -165,7 +165,7 @@ class AuraMonitor:
             self.update_vitality_status()
         else:
             self.update_status()
-            
+
         try:
             if self.status["lqs"]["active"] \
                 and self.status["lqs"]["mixer"]["in_filesystem_0"] \
@@ -179,7 +179,7 @@ class AuraMonitor:
         except Exception as e:
             self.logger.error("Exception while validating engine status: " + str(e))
             self.status["engine"]["status"] = MonitorResponseCode.INVALID_STATE.value
-        
+
         return is_valid
 
 
@@ -222,7 +222,7 @@ class AuraMonitor:
         self.status["lqs"]["mixer"]     = self.engine.player.mixer.mixer_status()
         self.status["lqs"]["mixer_fallback"] = self.engine.player.mixer_fallback.mixer_status()
         self.engine.player.connector.disable_transaction()
-    
+
         self.status["api"]["steering"]["url"]       = self.config.get("api_steering_status")
         self.status["api"]["steering"]["available"] = self.validate_url_connection(self.config.get("api_steering_status"))
 
@@ -243,7 +243,7 @@ class AuraMonitor:
         self.engine.player.connector.enable_transaction()
         self.status["lqs"]["active"]  = self.engine.is_connected()
         self.engine.player.connector.disable_transaction()
-        self.status["audio_source"] = self.validate_directory(self.config.get("audio_source_folder"))
+        self.status["audio_source"] = self.validate_directory(self.config.abs_audio_store_path())
 
         # After first update start the Heartbeat Monitor
         if not self.heartbeat_running:
@@ -259,14 +259,14 @@ class AuraMonitor:
         """
         if self.has_valid_status(True):
             self.heartbeat_socket.sendto(str.encode("OK"), (self.heartbeat_server, self.heartbeat_port))
-            
+
             # Engine resurrected into normal state
             if self.already_invalid:
                 self.already_invalid = False
                 status = json.dumps(self.get_status())
                 self.logger.info(SU.green("OK - Engine turned back into some healthy state!")+"\n"+str(status))
                 # Route call of event via event dispatcher to provide ability for additional hooks
-                self.engine.event_dispatcher.on_resurrect({"engine_id": self.engine_id, "status": status})                    
+                self.engine.event_dispatcher.on_resurrect({"engine_id": self.engine_id, "status": status})
         else:
             # Engine turned into invalid state
             if not self.already_invalid:
@@ -329,7 +329,7 @@ class AuraMonitor:
 
         Args:
             url (String):       The API endpoint to call
-        
+
         Returns:
             (dict[]):           A Python object representing the JSON structure
         """
diff --git a/src/plugins/trackservice.py b/src/plugins/trackservice.py
index 1373d48f2f11d9100afae4a075983f8c677983cd..28d6d7f36b6c17e7fee7eee65c16ac0695a56533 100644
--- a/src/plugins/trackservice.py
+++ b/src/plugins/trackservice.py
@@ -88,11 +88,11 @@ class TrackServiceHandler():
     def on_play(self, entry):
         """
         Some `PlaylistEntry` started playing. This is likely only a LIVE or STREAM entry.
-        """     
+        """
         content_class = ResourceUtil.get_content_class(entry.get_content_type())
         if content_class == ResourceClass.FILE:
             # Files are handled by "on_metadata" called via Liquidsoap
-            return 
+            return
 
         diff = (entry.entry_start_actual - entry.entry_start).total_seconds()
         self.logger.info("There's a difference of %s seconds between planned and actual start of the entry" % diff)
@@ -105,16 +105,16 @@ class TrackServiceHandler():
             data["track_title"] = entry.meta_data.title
         data["track_duration"] = entry.duration
         data["track_num"] = entry.entry_num
-        data["track_type"] = content_class.numeric   
+        data["track_type"] = content_class.numeric
         data["playlist_id"] = entry.playlist.playlist_id
         data["timeslot_id"] = entry.playlist.timeslot.timeslot_id
         data["show_id"] = entry.playlist.timeslot.show_id
         data["show_name"] = entry.playlist.timeslot.show_name
-        data["log_source"] = self.config.get("api_engine_number")    
+        data["log_source"] = self.config.get("api_engine_number")
 
         self.store_trackservice(data)
         self.store_clock_info(data)
-        
+
 
 
     def on_metadata(self, meta):
@@ -125,9 +125,9 @@ class TrackServiceHandler():
         data["track_start"] = meta.get("on_air")
         data["track_artist"] = meta.get("artist")
         data["track_album"] = meta.get("album")
-        data["track_title"] = meta.get("title")              
+        data["track_title"] = meta.get("title")
         data["track_type"] = ResourceClass.FILE.numeric
-        #lqs_source = meta["source"]  
+        #lqs_source = meta["source"]
 
         if "duration" in meta:
             duration = float(meta.get("duration"))
@@ -150,28 +150,28 @@ class TrackServiceHandler():
             if timeslot:
                 data = {**data, **timeslot}
                 data["playlist_id"] = -1
-        
+
         data["log_source"] = self.config.get("api_engine_number")
         data = SU.clean_dictionary(data)
         self.store_trackservice(data)
         self.store_clock_info(data)
 
-        
+
 
     def store_trackservice(self, data):
         """
         Posts the given `PlaylistEntry` to the Engine API Playlog.
-        """        
+        """
         data = SU.clean_dictionary(data)
 
-        self.logger.info("Posting playlog to Engine API...")        
+        self.logger.info("Posting playlog to Engine API...")
         url = self.config.get("api_engine_store_playlog")
         headers = {'content-type': 'application/json'}
         body = json.dumps(data, indent=4, sort_keys=True, default=str)
         self.logger.debug("Playlog Data: " + body)
         response = requests.post(url, data=body, headers=headers)
-        if response.status_code != 204 or response.status_code != 204:            
-            msg = f"Error while posting playlog to Engine API: {response.reason} (Error {response.status_code})\n"                
+        if response.status_code != 204 or response.status_code != 204:
+            msg = f"Error while posting playlog to Engine API: {response.reason} (Error {response.status_code})\n"
             self.logger.info(SU.red(msg) + response.content.decode("utf-8"))
 
 
@@ -182,12 +182,12 @@ class TrackServiceHandler():
         planned_playlist = None
         if self.engine.scheduler:
             (fallback_type, planned_playlist) = self.engine.scheduler.get_active_playlist()
-        (past_timeslot, current_timeslot, next_timeslot) = self.playlog.get_timeslots()            
+        (past_timeslot, current_timeslot, next_timeslot) = self.playlog.get_timeslots()
 
         data = dict()
-        data["engine_source"] = self.config.get("api_engine_number")        
+        data["engine_source"] = self.config.get("api_engine_number")
 
-        if current_timeslot:                        
+        if current_timeslot:
             data["current_timeslot"] = current_timeslot
 
             if planned_playlist:
@@ -199,14 +199,14 @@ class TrackServiceHandler():
                     entry["track_start"] = e.entry_start
                     if e.meta_data:
                         entry["track_artist"] = e.meta_data.artist
-                        entry["track_album"] = e.meta_data.album                
-                        entry["track_title"] = e.meta_data.title                
+                        entry["track_album"] = e.meta_data.album
+                        entry["track_title"] = e.meta_data.title
                     entry["track_num"] = e.entry_num
                     entry["track_duration"] = e.duration
                     content_class = ResourceUtil.get_content_class(e.get_content_type())
                     entry["track_type"] = content_class.numeric
                     entry = SU.clean_dictionary(entry)
-                    data["planned_playlist"]["entries"].append(entry) 
+                    data["planned_playlist"]["entries"].append(entry)
 
         if next_timeslot:
             data["next_timeslot"] = next_timeslot
@@ -214,15 +214,15 @@ class TrackServiceHandler():
 
         data = SU.clean_dictionary(data)
 
-        self.logger.info("Posting clock info update to Engine API...")        
+        self.logger.info("Posting clock info update to Engine API...")
         url = self.config.get("api_engine_store_clock")
         headers = {'content-type': 'application/json'}
         body = json.dumps(data, indent=4, sort_keys=True, default=str)
         self.logger.debug("Clock Data: " + body)
         response = requests.put(url, data=body, headers=headers)
-        if response.status_code != 204 or response.status_code != 204:            
-            msg = f"Error while posting clock-info to Engine API: {response.reason} (Error {response.status_code})\n"                
-            self.logger.info(SU.red(msg) + response.content.decode("utf-8"))   
+        if response.status_code != 204 or response.status_code != 204:
+            msg = f"Error while posting clock-info to Engine API: {response.reason} (Error {response.status_code})\n"
+            self.logger.info(SU.red(msg) + response.content.decode("utf-8"))
 
 
 
@@ -276,7 +276,7 @@ class Playlog:
 
         if next_timeslot:
             data["timeslot_end"] = next_timeslot.timeslot_start
-        else:        
+        else:
             data["timeslot_end"] = None
 
         self.current_timeslot = data
@@ -300,31 +300,31 @@ class Playlog:
 
         data = {}
         next_timeslot = self.engine.scheduler.get_programme().get_next_timeslots(1)
-        if next_timeslot: 
+        if next_timeslot:
             next_timeslot = next_timeslot[0]
         else:
             next_timeslot = None
-        
+
         # A valid timeslot from the scheduler is available
-        if timeslot:              
+        if timeslot:
             self.assign_fallback_playlist(data, timeslot)
             data["timeslot_id"] = timeslot.timeslot_id
             data["timeslot_start"] = timeslot.timeslot_start
-            data["timeslot_end"] = timeslot.timeslot_end            
+            data["timeslot_end"] = timeslot.timeslot_end
             data["show_id"] = timeslot.show_id
-            data["show_name"] = timeslot.show_name            
+            data["show_name"] = timeslot.show_name
             data = SU.clean_dictionary(data)
 
             # Any previous (fake) timeslots should get the proper end now
-            if not self.previous_timeslot:  
+            if not self.previous_timeslot:
                 self.current_timeslot["timeslot_end"] = timeslot.timeslot_start
-            self.previous_timeslot = self.current_timeslot       
+            self.previous_timeslot = self.current_timeslot
             self.current_timeslot = data
 
         # Defaults for a not existing timeslot
-        else:            
+        else:
             self.init_timeslot(next_timeslot)
-            
+
         # A valid following timeslot is available
         self.next_timeslot = None
         if next_timeslot:
@@ -353,7 +353,7 @@ class Playlog:
         playlist = None
 
         if timeslot:
-            fallback_type, playlist = self.engine.scheduler.fallback.resolve_playlist(timeslot)  
+            fallback_type, playlist = self.engine.scheduler.fallback.resolve_playlist(timeslot)
 
         if playlist:
             data["playlist_id"] = playlist.playlist_id
@@ -380,7 +380,7 @@ class Playlog:
         """
         Saves the currently preloaded [`Entry`] to the local cache.
         """
-        self.history.append(entry) 
+        self.history.append(entry)
 
 
     def get_recent_entries(self):
@@ -392,7 +392,7 @@ class Playlog:
 
     def resolve_entry(self, uri):
         """
-        Retrieves the playlog matching the provied file URI.
+        Retrieves the playlog matching the provided file URI.
 
         Args:
             path (String):    The URI of the resource
@@ -407,7 +407,7 @@ class Playlog:
                 entry_source = entry.source
 
                 if entry.get_content_type() in ResourceClass.FILE.types:
-                    base_dir = self.config.get("audio_source_folder")
+                    base_dir = self.config.abs_audio_store_path()
                     extension = self.config.get("audio_source_extension")
                     entry_source = ResourceUtil.source_to_filepath(base_dir, entry.source, extension)
                 if entry_source == uri:
diff --git a/src/scheduling/utils.py b/src/scheduling/utils.py
index f406442092b44ab56b9368facfc78cad94c0b698..80c8c1e06609bc6103a166eb9aa10d93719d01f6 100644
--- a/src/scheduling/utils.py
+++ b/src/scheduling/utils.py
@@ -47,9 +47,9 @@ class TimeslotFilter():
 
     @staticmethod
     def filter_24h(timeslots):
-        """ 
+        """
         Removes entries 24h in the future and 12 hours in the past.
-        Note: This might influence resuming (in case of a crash)  
+        Note: This might influence resuming (in case of a crash)
         single timeslots which are longer than 12 hours long.
         Think e.g. live broadcasts.
         """
@@ -71,7 +71,7 @@ class TimeslotFilter():
     @staticmethod
     def filter_past(timeslots):
         """
-        Removes all timeslot dictionaries from the past, except the one which is 
+        Removes all timeslot dictionaries from the past, except the one which is
         currently playing.
         """
         items = []
@@ -108,9 +108,7 @@ class M3UPlaylistProcessor():
         """
         self.config = AuraConfig.config()
         self.logger = logging.getLogger("AuraEngine")
-        self.playlist_folder = self.config.get("audio_playlist_folder")
-        if not self.playlist_folder.endswith("/"):
-            self.playlist_folder += "/"
+        self.playlist_folder = self.config.abs_playlist_path()
 
 
 
@@ -127,7 +125,7 @@ class M3UPlaylistProcessor():
         for entry in entries:
             # It's a M3U Playlist which needs to be spread
             if "uri" in entry and entry["uri"].startswith("playlist://"):
-                
+
                 playlist_name = entry["uri"].split("playlist://")[1]
                 self.logger.info(f"Spreading entries of M3U playlist '{playlist_name}'")
                 m3u_entries = self.read_m3u_file(self.playlist_folder + playlist_name)
@@ -189,7 +187,7 @@ class TimeslotRenderer:
 
     def get_ascii_timeslots(self):
         """
-        Creates a printable version of the current programme (playlists and entries as per timeslot) 
+        Creates a printable version of the current programme (playlists and entries as per timeslot)
 
         Returns:
             (String):   An ASCII representation of the current and next timeslots
@@ -206,13 +204,13 @@ class TimeslotRenderer:
             (fallback_type, resolved_playlist) = self.scheduler.fallback.resolve_playlist(active_timeslot)
 
             s += "\n│   Playing timeslot %s         " % active_timeslot
-            if planned_playlist: 
+            if planned_playlist:
                 if resolved_playlist and resolved_playlist.playlist_id != planned_playlist.playlist_id:
                     s += "\n│       └── Playlist %s         " % planned_playlist
                     s += "\n│       "
                     s += SU.red("↑↑↑ That's the originally planned playlist.") + ("Instead playing the fallback playlist below ↓↓↓")
 
-            if resolved_playlist:                                  
+            if resolved_playlist:
                 if not planned_playlist:
                     s += "\n│                         "
                     s += SU.red("No playlist assigned to timeslot. Instead playing the `%s` playlist below ↓↓↓" % SU.cyan(str(fallback_type)))
@@ -237,7 +235,7 @@ class TimeslotRenderer:
                     rest_of_playlist = active_entry.get_next_entries(False)
                     entries = self.preprocess_entries(rest_of_playlist, False)
                     s += self.build_playlist_string(entries)
-                    
+
             else:
                 s += "\n│       └── %s" % (SU.red("No active playlist. There should be at least some fallback playlist running..."))
         else:
@@ -251,7 +249,7 @@ class TimeslotRenderer:
         if not next_timeslots:
             s += "\n│   Nothing.         "
         else:
-            for timeslot in next_timeslots:        
+            for timeslot in next_timeslots:
                 (fallback_type, resolved_playlist) = self.scheduler.fallback.resolve_playlist(timeslot)
                 if resolved_playlist:
 
@@ -260,7 +258,7 @@ class TimeslotRenderer:
                     if resolved_playlist.end_unix > timeslot.end_unix:
                         s += "\n│          %s!              " % \
                         (SU.red("↑↑↑ Playlist #%s ends after timeslot #%s!" % (resolved_playlist.playlist_id, timeslot.timeslot_id)))
-                    
+
                     entries = self.preprocess_entries(resolved_playlist.entries, False)
                     s += self.build_playlist_string(entries)
 
@@ -268,7 +266,7 @@ class TimeslotRenderer:
         return s
 
 
-    
+
     def build_playlist_string(self, entries):
         """
         Returns a stringified list of entries
@@ -329,7 +327,7 @@ class TimeslotRenderer:
                 entry.queue_state = EntryQueueState.CUT
             else:
                 entry.queue_state = EntryQueueState.OKAY
-            
+
             if not entry.queue_state == EntryQueueState.OUT_OF_SCHEDULE or not cut_oos:
                 clean_entries.append(entry)