diff --git a/src/channels.py b/src/channels.py index 3a0be4af8cc31a1a4f7664c9906d094f4b6facff..c3744836bb686b8181e8fd831e8fcb49e84505d8 100644 --- a/src/channels.py +++ b/src/channels.py @@ -46,7 +46,7 @@ class Channel(Enum): LIVE_3 = "linein_3" LIVE_4 = "linein_4" FALLBACK_QUEUE_A = "in_fallback_scheduled_0" - FALLBACK_QUEUE_B = "in_fallback_scheduled_1" + FALLBACK_QUEUE_B = "in_fallback_scheduled_1" FALLBACK_STATION_FOLDER = "station_folder" FALLBACK_STATION_PLAYLIST = "station_playlist" @@ -54,6 +54,33 @@ class Channel(Enum): return str(self.value) +class ChannelResolver(): + """ + Helpers for resolving channel enumerations. + """ + + @staticmethod + def live_channel_for_resource(channel: str): + """ + Returns the channel enum for a given channel string. + """ + if not channel: return None + channel = "linein_" + channel.split("line://")[1] + + if channel == Channel.LIVE_0.value: + return Channel.LIVE_0 + elif channel == Channel.LIVE_1.value: + return Channel.LIVE_2 + elif channel == Channel.LIVE_3.value: + return Channel.LIVE_3 + elif channel == Channel.LIVE_4.value: + return Channel.LIVE_4 + elif channel == Channel.LIVE_5.value: + return Channel.LIVE_5 + else: + return None + + class ChannelType(Enum): """ Engine channel types mapped to `Entry` source types. @@ -77,7 +104,7 @@ class ChannelType(Enum): "id": "live", "numeric": 3, "channels": [ - Channel.LIVE_0, + Channel.LIVE_0, Channel.LIVE_1, Channel.LIVE_2, Channel.LIVE_3, @@ -88,7 +115,7 @@ class ChannelType(Enum): "id": "fallback_queue", "numeric": 4, "channels": [Channel.FALLBACK_QUEUE_A, Channel.FALLBACK_QUEUE_B] - } + } FALLBACK_POOL = { "id": "fallback_pool", "numeric": 5, @@ -119,7 +146,7 @@ class LiquidsoapResponse(Enum): STREAM_STATUS_POLLING = "polling" STREAM_STATUS_STOPPED = "stopped" STREAM_STATUS_CONNECTED = "connected" - + class ChannelRouter(): @@ -142,7 +169,7 @@ class ChannelRouter(): """ self.config = config self.logger = logger - + self.resource_mapping = { ResourceType.FILE: ChannelType.QUEUE, ResourceType.STREAM_HTTP: ChannelType.HTTP, @@ -159,8 +186,8 @@ class ChannelRouter(): ChannelType.HTTPS: Channel.HTTPS_A, ChannelType.LIVE: Channel.LIVE_0 } - - + + def set_active(self, channel_type, channel): """ Set the channel for the given resource type active @@ -177,7 +204,7 @@ class ChannelRouter(): def type_of_channel(self, channel): """ - Retrieves a `ChannelType` for the given `Channel`. + Retrieves a `ChannelType` for the given `Channel`. """ if channel in ChannelType.QUEUE.channels: return ChannelType.QUEUE @@ -198,7 +225,7 @@ class ChannelRouter(): Retrieves a `ChannelType` for the given `ResourceType`. Only default mappings can be evaluatated. Custom variations - like fallback channels are not respected. + like fallback channels are not respected. """ return self.resource_mapping.get(resource_type) @@ -254,7 +281,7 @@ class ChannelRouter(): else: new_channel = Channel.HTTPS_A msg = "Swapped HTTPS Stream channel from B > A" - + else: self.logger.warning(SU.red(f"No channel to swap - invalid entry_type '{channel_type}'")) diff --git a/src/engine.py b/src/engine.py index 07e5e9ebe2f761bf669ca9251185b91c71b4be38..b0f23aac0c32aced5756226b5c6f0cae505ceee4 100644 --- a/src/engine.py +++ b/src/engine.py @@ -29,7 +29,7 @@ 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.channels import ChannelType, TransitionType, LiquidsoapResponse, EntryPlayState, ResourceType, ChannelRouter +from src.channels import ChannelType, TransitionType, LiquidsoapResponse, EntryPlayState, ResourceType, ChannelRouter, ChannelResolver from src.events import EngineEventDispatcher from src.control import EngineControlInterface from src.mixer import Mixer, MixerType @@ -229,7 +229,10 @@ class Player: # LIVE if entry.get_content_type() in ResourceClass.LIVE.types: - entry.channel = "linein_" + entry.source.split("line://")[1] + entry.channel = ChannelResolver.live_channel_for_resource(entry.source) + if entry.channel == None: + self.logger.critical(SU.red("Invalid live channel '{entry.source}' requested!")) + entry.previous_channel = None is_ready = True else: channel_type = self.channel_router.type_for_resource(entry.get_content_type()) diff --git a/src/resources.py b/src/resources.py index 3797f8d8c4ddccac17433918ded49f3a9ede824c..d2126019428b35964ca5e5a1eaae417fa9c0b162 100644 --- a/src/resources.py +++ b/src/resources.py @@ -24,7 +24,7 @@ from enum import Enum class ResourceType(Enum): """ Media content types. - """ + """ FILE = "file:" STREAM_HTTP = "http:" STREAM_HTTPS = "https:" @@ -135,7 +135,7 @@ class ResourceUtil(Enum): file = open(target_file, "w") fb = [ "#EXTM3U" ] - for entry in entries: + for entry in entries: if ResourceUtil.get_content_type(entry.source) == ResourceType.FILE: path = ResourceUtil.source_to_filepath(audio_store_path, entry.source, entry_extension) fb.append(f"#EXTINF:{entry.duration},{entry.meta_data.artist} - {entry.meta_data.title}") @@ -148,7 +148,7 @@ class ResourceUtil(Enum): @staticmethod def source_to_filepath(base_dir, source, source_extension): """ - Converts a file-system URI starting with "file://" to an actual, + Converts a file-system URI starting with "file://" to an actual, absolute path to the file, appending the extension as provided in "source_extension". @@ -166,7 +166,7 @@ class ResourceUtil(Enum): path = source[7:] if path.startswith("/"): return path - else: + else: return base_dir + "/" + path + source_extension @@ -193,10 +193,10 @@ class ResourceUtil(Enum): Args: uri (String): The path to the audio source cue_in (Float): The value in seconds wher the cue in should start - + Returns: (String): The annotated URI """ if cue_in > 0.0: uri = "annotate:liq_cue_in=\"%s\":%s" % (str(cue_in), uri) - return uri \ No newline at end of file + return uri \ No newline at end of file