From b9368d1b7b0bfac3c3a85b7befdb25660a0598dc Mon Sep 17 00:00:00 2001 From: jo Date: Wed, 10 Aug 2022 17:33:22 +0200 Subject: [PATCH] feat(playout): build liquidsoap entrypoint with stream config --- playout/libretime_playout/config.py | 8 +- .../liquidsoap/1.1/ls_script.liq | 19 +-- .../liquidsoap/1.3/ls_script.liq | 19 +-- .../liquidsoap/1.4/ls_script.liq | 19 +-- .../liquidsoap/entrypoint.liq.j2 | 61 +++++++++ .../liquidsoap/entrypoint.py | 116 +++++++++--------- playout/libretime_playout/liquidsoap/main.py | 32 ++++- .../libretime_playout/liquidsoap/models.py | 27 ++++ playout/requirements.txt | 1 + playout/setup.py | 3 +- playout/tests/conftest.py | 37 ++++++ playout/tests/fixtures/__init__.py | 11 +- playout/tests/fixtures/entrypoint-1.1.liq | 105 ++++++++++++++++ playout/tests/fixtures/entrypoint-1.4.liq | 105 ++++++++++++++++ playout/tests/liquidsoap/entrypoint_test.py | 43 +++++++ 15 files changed, 486 insertions(+), 120 deletions(-) create mode 100644 playout/libretime_playout/liquidsoap/entrypoint.liq.j2 create mode 100644 playout/libretime_playout/liquidsoap/models.py create mode 100644 playout/tests/conftest.py create mode 100644 playout/tests/fixtures/entrypoint-1.1.liq create mode 100644 playout/tests/fixtures/entrypoint-1.4.liq create mode 100644 playout/tests/liquidsoap/entrypoint_test.py diff --git a/playout/libretime_playout/config.py b/playout/libretime_playout/config.py index dac238293..19897985f 100644 --- a/playout/libretime_playout/config.py +++ b/playout/libretime_playout/config.py @@ -1,6 +1,11 @@ from pathlib import Path -from libretime_shared.config import BaseConfig, GeneralConfig, RabbitMQConfig +from libretime_shared.config import ( + BaseConfig, + GeneralConfig, + RabbitMQConfig, + StreamConfig, +) from pydantic import BaseModel from typing_extensions import Literal @@ -26,3 +31,4 @@ class Config(BaseConfig): general: GeneralConfig rabbitmq: RabbitMQConfig = RabbitMQConfig() playout: PlayoutConfig = PlayoutConfig() + stream: StreamConfig = StreamConfig() diff --git a/playout/libretime_playout/liquidsoap/1.1/ls_script.liq b/playout/libretime_playout/liquidsoap/1.1/ls_script.liq index 6b2a0ce28..7d3bd496e 100644 --- a/playout/libretime_playout/liquidsoap/1.1/ls_script.liq +++ b/playout/libretime_playout/liquidsoap/1.1/ls_script.liq @@ -1,28 +1,11 @@ -%include "/etc/libretime/liquidsoap.cfg" - -if (log_file != "") then - set("log.file.path", log_file) -else - set("log.file", false) -end - -set("server.telnet", true) -set("server.telnet.port", 1234) +time = ref string_of(gettimeofday()) #Dynamic source list #dyn_sources = ref [] webstream_enabled = ref false -time = ref string_of(gettimeofday()) - -#live stream setup -set("harbor.bind_addr", "0.0.0.0") - current_dyn_id = ref '-1' -stream_metadata_type = ref 0 -default_dj_fade = ref 0. -station_name = ref '' show_name = ref '' dynamic_metadata_callback = ref fun (s) -> begin () end diff --git a/playout/libretime_playout/liquidsoap/1.3/ls_script.liq b/playout/libretime_playout/liquidsoap/1.3/ls_script.liq index cbcbfd619..163d17462 100644 --- a/playout/libretime_playout/liquidsoap/1.3/ls_script.liq +++ b/playout/libretime_playout/liquidsoap/1.3/ls_script.liq @@ -1,28 +1,11 @@ -%include "/etc/libretime/liquidsoap.cfg" - -if (log_file != "") then - set("log.file.path", log_file) -else - set("log.file", false) -end - -set("server.telnet", true) -set("server.telnet.port", 1234) +time = ref string_of(gettimeofday()) #Dynamic source list #dyn_sources = ref [] webstream_enabled = ref false -time = ref string_of(gettimeofday()) - -#live stream setup -set("harbor.bind_addrs", ["0.0.0.0"]) - current_dyn_id = ref '-1' -stream_metadata_type = ref 0 -default_dj_fade = ref 0. -station_name = ref '' show_name = ref '' dynamic_metadata_callback = ref fun (s) -> begin () end diff --git a/playout/libretime_playout/liquidsoap/1.4/ls_script.liq b/playout/libretime_playout/liquidsoap/1.4/ls_script.liq index 502784c08..ebfd3ac5d 100644 --- a/playout/libretime_playout/liquidsoap/1.4/ls_script.liq +++ b/playout/libretime_playout/liquidsoap/1.4/ls_script.liq @@ -1,28 +1,11 @@ -%include "/etc/libretime/liquidsoap.cfg" - -if (log_file != "") then - set("log.file.path", log_file) -else - set("log.file", false) -end - -set("server.telnet", true) -set("server.telnet.port", 1234) +time = ref string_of(gettimeofday()) #Dynamic source list #dyn_sources = ref [] webstream_enabled = ref false -time = ref string_of(gettimeofday()) - -#live stream setup -set("harbor.bind_addrs", ["0.0.0.0"]) - current_dyn_id = ref '-1' -stream_metadata_type = ref 0 -default_dj_fade = ref 0. -station_name = ref '' show_name = ref '' dynamic_metadata_callback = ref fun (~new_track=false, s) -> begin () end diff --git a/playout/libretime_playout/liquidsoap/entrypoint.liq.j2 b/playout/libretime_playout/liquidsoap/entrypoint.liq.j2 new file mode 100644 index 000000000..d6a84de96 --- /dev/null +++ b/playout/libretime_playout/liquidsoap/entrypoint.liq.j2 @@ -0,0 +1,61 @@ +# THIS FILE IS AUTO GENERATED. PLEASE DO NOT EDIT! +########################################################### +# The ignore() lines are to squash unused variable warnings + +# Inputs +master_live_stream_mp = "{{ config.stream.inputs.main.mount }}" +master_live_stream_port = {{ config.stream.inputs.main.port }} +dj_live_stream_mp = "{{ config.stream.inputs.show.mount }}" +dj_live_stream_port = {{ config.stream.inputs.show.port }} + +{% for output in config.stream.outputs.merged -%} +# Output s{{ loop.index }} +s{{ loop.index }}_enable = {{ output.enabled | lower }} +s{{ loop.index }}_output = "{{ output.kind }}" +s{{ loop.index }}_host = "{{ output.host }}" +s{{ loop.index }}_port = {{ output.port }} +s{{ loop.index }}_mount = "{{ output.mount }}" +s{{ loop.index }}_user = "{{ output.source_user }}" +s{{ loop.index }}_pass = "{{ output.source_password }}" + +s{{ loop.index }}_channels = "{{ output.audio.channels.value }}" +s{{ loop.index }}_type = "{{ output.audio.format.value }}" +s{{ loop.index }}_bitrate = {{ output.audio.bitrate }} + +s{{ loop.index }}_name = "{{ output.name or '' }}" +s{{ loop.index }}_description = "{{ output.description or '' }}" +s{{ loop.index }}_genre = "{{ output.genre or '' }}" +s{{ loop.index }}_url = "{{ output.website or '' }}" + +{% endfor -%} +icecast_vorbis_metadata = {{ icecast_vorbis_metadata | lower }} + +# System output +output_sound_device = {{ config.stream.outputs.system[0].enabled | lower }} +output_sound_device_type = "{{ config.stream.outputs.system[0].kind.value }}" + +# Settings +auth_path = "{{ paths.auth_filepath }}" + +{% if paths.log_filepath is defined -%} +set("log.file.path", "{{ paths.log_filepath }}") +{%- else -%} +set("log.file", false) +{%- endif %} + +set("server.telnet", true) +set("server.telnet.port", 1234) + +{% if version >= (1, 3, 3) -%} +set("harbor.bind_addrs", ["0.0.0.0"]) +{%- else -%} +set("harbor.bind_addr", "0.0.0.0") +{%- endif %} + +station_name = ref "{{ info.station_name }}" + +off_air_meta = "{{ preferences.message_offline }}" +stream_metadata_type = ref {{ preferences.message_format.value }} +default_dj_fade = ref {{ preferences.input_fade_transition }} + +%include "{{ paths.lib_filepath }}" diff --git a/playout/libretime_playout/liquidsoap/entrypoint.py b/playout/libretime_playout/liquidsoap/entrypoint.py index 68c06e88e..2acaa51b6 100644 --- a/playout/libretime_playout/liquidsoap/entrypoint.py +++ b/playout/libretime_playout/liquidsoap/entrypoint.py @@ -1,64 +1,70 @@ -import os -import sys -import time from pathlib import Path -from typing import Optional +from typing import Optional, Tuple -from libretime_api_client.v1 import ApiClient as LegacyClient -from loguru import logger +from jinja2 import Template +from libretime_shared.config import AudioFormat, IcecastOutput, SystemOutput + +from ..config import Config +from .models import Info, StreamPreferences + +here = Path(__file__).parent + +entrypoint_template_path = here / "entrypoint.liq.j2" +entrypoint_template = Template( + entrypoint_template_path.read_text(encoding="utf-8"), + keep_trailing_newline=True, +) + +# Liquidsoap has 4 hardcoded output stream set of variables, so we need to +# fill the missing stream outputs with placeholders so Liquidsoap does +# not fail with missing variables in the entrypoint. +_icecast_placeholder = IcecastOutput( + enabled=False, + mount="", + source_password="", + audio=dict(format="ogg", bitrate=256), +) + +_system_placeholder = SystemOutput() -def generate_liquidsoap_config(ss, log_filepath: Optional[Path]): - data = ss["msg"] - fh = open("/etc/libretime/liquidsoap.cfg", "w") - fh.write("################################################\n") - fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n") - fh.write("################################################\n") - fh.write("# The ignore() lines are to squash unused variable warnings\n") +def generate_entrypoint( + entrypoint_filepath: Path, + log_filepath: Optional[Path], + config: Config, + preferences: StreamPreferences, + info: Info, + version: Tuple[int, int, int], +): + paths = {} + paths["auth_filepath"] = here / "liquidsoap_auth.py" + paths["lib_filepath"] = here / f"{version[0]}.{version[1]}/ls_script.liq" - for key, value in data.items(): - try: - if not "port" in key and not "bitrate" in key: # Stupid hack - raise ValueError() - str_buffer = f"{key} = {int(value)}\n" - except ValueError: - try: # Is it a boolean? - if value == "true" or value == "false": - str_buffer = f"{key} = {value.lower()}\n" - else: - raise ValueError() # Just drop into the except below - except: # Everything else is a string - str_buffer = f'{key} = "{value}"\n' + if log_filepath is not None: + paths["log_filepath"] = log_filepath.resolve() - fh.write(str_buffer) - # ignore squashes unused variable errors from Liquidsoap - fh.write("ignore(%s)\n" % key) + config = config.copy() + missing_outputs = [_icecast_placeholder] * (4 - len(config.stream.outputs.merged)) + config.stream.outputs.icecast.extend(missing_outputs) - auth_path = os.path.dirname(os.path.realpath(__file__)) - log_file = log_filepath.resolve() if log_filepath is not None else "" + if not config.stream.outputs.system: + config.stream.outputs.system.append(_system_placeholder) - fh.write(f'log_file = "{log_file}"\n') - fh.write('auth_path = "%s/liquidsoap_auth.py"\n' % auth_path) - fh.close() + # Global icecast_vorbis_metadata until it is + # handled per output + icecast_vorbis_metadata = any( + o.enabled and o.audio.format == AudioFormat.OGG and o.audio.enable_metadata # type: ignore + for o in config.stream.outputs.icecast + ) - -def generate_entrypoint(log_filepath: Optional[Path]): - attempts = 0 - max_attempts = 10 - successful = False - - while not successful: - try: - legacy_client = LegacyClient(logger) - ss = legacy_client.get_stream_setting() - generate_liquidsoap_config(ss, log_filepath) - successful = True - except Exception: - logger.exception("Unable to connect to the Airtime server") - if attempts == max_attempts: - logger.error("giving up and exiting...") - sys.exit(1) - else: - logger.info("Retrying in 3 seconds...") - time.sleep(3) - attempts += 1 + entrypoint_filepath.write_text( + entrypoint_template.render( + config=config, + preferences=preferences, + info=info, + paths=paths, + version=version, + icecast_vorbis_metadata=icecast_vorbis_metadata, + ), + encoding="utf-8", + ) diff --git a/playout/libretime_playout/liquidsoap/main.py b/playout/libretime_playout/liquidsoap/main.py index 1f5a195db..717ab436a 100644 --- a/playout/libretime_playout/liquidsoap/main.py +++ b/playout/libretime_playout/liquidsoap/main.py @@ -3,12 +3,15 @@ from pathlib import Path from typing import Optional import click -from libretime_shared.cli import cli_logging_options +from libretime_api_client.v2 import ApiClient +from libretime_shared.cli import cli_config_options, cli_logging_options from libretime_shared.config import DEFAULT_ENV_PREFIX from libretime_shared.logging import level_from_name, setup_logger from loguru import logger +from ..config import Config from .entrypoint import generate_entrypoint +from .models import Info, StreamPreferences from .version import get_liquidsoap_version here = Path(__file__).parent @@ -16,25 +19,42 @@ here = Path(__file__).parent @click.command(context_settings={"auto_envvar_prefix": DEFAULT_ENV_PREFIX}) @cli_logging_options() -def cli(log_level: str, log_filepath: Optional[Path]): +@cli_config_options() +def cli(log_level: str, log_filepath: Optional[Path], config_filepath: Optional[Path]): """ Run liquidsoap. """ logger_level, _ = setup_logger(level_from_name(log_level), log_filepath) + config = Config(config_filepath) - generate_entrypoint(log_filepath) + api_client = ApiClient( + base_url=config.general.public_url, + api_key=config.general.api_key, + ) version = get_liquidsoap_version() - script_path = here / f"{version[0]}.{version[1]}/ls_script.liq" + info = Info(**api_client.get_info().json()) + preferences = StreamPreferences(**api_client.get_stream_preferences().json()) + + entrypoint_filepath = Path.cwd() / "radio.liq" + generate_entrypoint( + entrypoint_filepath, + log_filepath, + config, + preferences, + info, + version, + ) + exec_args = [ "/usr/bin/liquidsoap", "libretime-liquidsoap", "--verbose", - str(script_path), + str(entrypoint_filepath), ] if logger_level.is_debug(): exec_args.append("--debug") - logger.debug(f"Liquidsoap {version} using script: {script_path}") + logger.debug(f"liquidsoap {version} using script: {entrypoint_filepath}") os.execl(*exec_args) diff --git a/playout/libretime_playout/liquidsoap/models.py b/playout/libretime_playout/liquidsoap/models.py new file mode 100644 index 000000000..c8d9520fe --- /dev/null +++ b/playout/libretime_playout/liquidsoap/models.py @@ -0,0 +1,27 @@ +from enum import Enum + +from pydantic import BaseModel + + +class Info(BaseModel): + station_name: str + + +class MessageFormatKind(int, Enum): + ARTIST_TITLE = 0 + SHOW_ARTIST_TITLE = 1 + RADIO_SHOW = 2 + + +class StreamPreferences(BaseModel): + input_fade_transition: float + message_format: MessageFormatKind + message_offline: str + + +class StreamState(BaseModel): + input_main_connected: bool + input_main_streaming: bool + input_show_connected: bool + input_show_streaming: bool + schedule_streaming: bool diff --git a/playout/requirements.txt b/playout/requirements.txt index 3a06dccab..9e5f94b15 100644 --- a/playout/requirements.txt +++ b/playout/requirements.txt @@ -2,6 +2,7 @@ # This file is auto-generated by tools/extract_requirements.py. backports.zoneinfo>=0.2.1,<0.3;python_version<'3.9' dataclasses>=0.8,<0.9;python_version<'3.7' +jinja2>=3.0.3,<3.2 kombu==4.6.11 lxml>=4.5.0,<4.10.0 mutagen>=1.45.1,<1.46 diff --git a/playout/setup.py b/playout/setup.py index b85d24969..24f8c2289 100644 --- a/playout/setup.py +++ b/playout/setup.py @@ -13,7 +13,7 @@ setup( }, license="AGPLv3", packages=find_packages(exclude=["*tests*", "*fixtures*"]), - package_data={"": ["**/*.liq", "*.types"]}, + package_data={"": ["**/*.liq", "**/*.liq.j2", "*.types"]}, entry_points={ "console_scripts": [ "libretime-playout=libretime_playout.main:cli", @@ -25,6 +25,7 @@ setup( install_requires=[ "backports.zoneinfo>=0.2.1,<0.3;python_version<'3.9'", "dataclasses>=0.8,<0.9;python_version<'3.7'", + "jinja2>=3.0.3,<3.2", "kombu==4.6.11", "lxml>=4.5.0,<4.10.0", "mutagen>=1.45.1,<1.46", diff --git a/playout/tests/conftest.py b/playout/tests/conftest.py new file mode 100644 index 000000000..d9f24e4e2 --- /dev/null +++ b/playout/tests/conftest.py @@ -0,0 +1,37 @@ +import pytest + +from libretime_playout.config import Config + + +@pytest.fixture(scope="session") +def config(): + return Config( + **{ + "general": { + "public_url": "http://localhost:8080", + "api_key": "some_api_key", + }, + "stream": { + "outputs": { + "icecast": [ + { + "enabled": True, + "mount": "main", + "source_password": "hackme", + "audio": {"format": "ogg", "bitrate": 256}, + "name": "LibreTime!", + "description": "LibreTime Radio! Stream #1", + "website": "https://libretime.org", + "genre": "various", + }, + { + "enabled": True, + "mount": "second", + "source_password": "hackme", + "audio": {"format": "mp3", "bitrate": 256}, + }, + ] + } + }, + } + ) diff --git a/playout/tests/fixtures/__init__.py b/playout/tests/fixtures/__init__.py index c94703c11..d0f5ebe60 100644 --- a/playout/tests/fixtures/__init__.py +++ b/playout/tests/fixtures/__init__.py @@ -1,6 +1,11 @@ from pathlib import Path -fixture_path = Path(__file__).parent +fixtures_path = Path(__file__).parent -icecast_stats = fixture_path / "icecast_stats.xml" -shoutcast_admin = fixture_path / "shoutcast_admin.xml" +icecast_stats = fixtures_path / "icecast_stats.xml" +shoutcast_admin = fixtures_path / "shoutcast_admin.xml" + +entrypoint_1_1 = fixtures_path / "entrypoint-1.1.liq" +entrypoint_1_1_snapshot = entrypoint_1_1.read_text(encoding="utf-8") +entrypoint_1_4 = fixtures_path / "entrypoint-1.4.liq" +entrypoint_1_4_snapshot = entrypoint_1_4.read_text(encoding="utf-8") diff --git a/playout/tests/fixtures/entrypoint-1.1.liq b/playout/tests/fixtures/entrypoint-1.1.liq new file mode 100644 index 000000000..848d31350 --- /dev/null +++ b/playout/tests/fixtures/entrypoint-1.1.liq @@ -0,0 +1,105 @@ +# THIS FILE IS AUTO GENERATED. PLEASE DO NOT EDIT! +########################################################### +# The ignore() lines are to squash unused variable warnings + +# Inputs +master_live_stream_mp = "main" +master_live_stream_port = 8001 +dj_live_stream_mp = "show" +dj_live_stream_port = 8002 + +# Output s1 +s1_enable = true +s1_output = "icecast" +s1_host = "localhost" +s1_port = 8000 +s1_mount = "main" +s1_user = "source" +s1_pass = "hackme" + +s1_channels = "stereo" +s1_type = "ogg" +s1_bitrate = 256 + +s1_name = "LibreTime!" +s1_description = "LibreTime Radio! Stream #1" +s1_genre = "various" +s1_url = "https://libretime.org" + +# Output s2 +s2_enable = true +s2_output = "icecast" +s2_host = "localhost" +s2_port = 8000 +s2_mount = "second" +s2_user = "source" +s2_pass = "hackme" + +s2_channels = "stereo" +s2_type = "mp3" +s2_bitrate = 256 + +s2_name = "" +s2_description = "" +s2_genre = "" +s2_url = "" + +# Output s3 +s3_enable = false +s3_output = "icecast" +s3_host = "localhost" +s3_port = 8000 +s3_mount = "" +s3_user = "source" +s3_pass = "" + +s3_channels = "stereo" +s3_type = "ogg" +s3_bitrate = 256 + +s3_name = "" +s3_description = "" +s3_genre = "" +s3_url = "" + +# Output s4 +s4_enable = false +s4_output = "icecast" +s4_host = "localhost" +s4_port = 8000 +s4_mount = "" +s4_user = "source" +s4_pass = "" + +s4_channels = "stereo" +s4_type = "ogg" +s4_bitrate = 256 + +s4_name = "" +s4_description = "" +s4_genre = "" +s4_url = "" + +icecast_vorbis_metadata = false + +# System output +output_sound_device = false +output_sound_device_type = "alsa" + +# Settings +auth_path = "/fake/liquidsoap_auth.py" + +set("log.file.path", "/var/log/radio.log") + +set("server.telnet", true) +set("server.telnet.port", 1234) + +set("harbor.bind_addr", "0.0.0.0") + +station_name = ref "LibreTime" + +off_air_meta = "LibreTime - offline" +stream_metadata_type = ref 0 +default_dj_fade = ref 0.0 + +%include "/fake/1.1/ls_script.liq" diff --git a/playout/tests/fixtures/entrypoint-1.4.liq b/playout/tests/fixtures/entrypoint-1.4.liq new file mode 100644 index 000000000..7060ecef9 --- /dev/null +++ b/playout/tests/fixtures/entrypoint-1.4.liq @@ -0,0 +1,105 @@ +# THIS FILE IS AUTO GENERATED. PLEASE DO NOT EDIT! +########################################################### +# The ignore() lines are to squash unused variable warnings + +# Inputs +master_live_stream_mp = "main" +master_live_stream_port = 8001 +dj_live_stream_mp = "show" +dj_live_stream_port = 8002 + +# Output s1 +s1_enable = true +s1_output = "icecast" +s1_host = "localhost" +s1_port = 8000 +s1_mount = "main" +s1_user = "source" +s1_pass = "hackme" + +s1_channels = "stereo" +s1_type = "ogg" +s1_bitrate = 256 + +s1_name = "LibreTime!" +s1_description = "LibreTime Radio! Stream #1" +s1_genre = "various" +s1_url = "https://libretime.org" + +# Output s2 +s2_enable = true +s2_output = "icecast" +s2_host = "localhost" +s2_port = 8000 +s2_mount = "second" +s2_user = "source" +s2_pass = "hackme" + +s2_channels = "stereo" +s2_type = "mp3" +s2_bitrate = 256 + +s2_name = "" +s2_description = "" +s2_genre = "" +s2_url = "" + +# Output s3 +s3_enable = false +s3_output = "icecast" +s3_host = "localhost" +s3_port = 8000 +s3_mount = "" +s3_user = "source" +s3_pass = "" + +s3_channels = "stereo" +s3_type = "ogg" +s3_bitrate = 256 + +s3_name = "" +s3_description = "" +s3_genre = "" +s3_url = "" + +# Output s4 +s4_enable = false +s4_output = "icecast" +s4_host = "localhost" +s4_port = 8000 +s4_mount = "" +s4_user = "source" +s4_pass = "" + +s4_channels = "stereo" +s4_type = "ogg" +s4_bitrate = 256 + +s4_name = "" +s4_description = "" +s4_genre = "" +s4_url = "" + +icecast_vorbis_metadata = false + +# System output +output_sound_device = false +output_sound_device_type = "alsa" + +# Settings +auth_path = "/fake/liquidsoap_auth.py" + +set("log.file.path", "/var/log/radio.log") + +set("server.telnet", true) +set("server.telnet.port", 1234) + +set("harbor.bind_addrs", ["0.0.0.0"]) + +station_name = ref "LibreTime" + +off_air_meta = "LibreTime - offline" +stream_metadata_type = ref 0 +default_dj_fade = ref 0.0 + +%include "/fake/1.4/ls_script.liq" diff --git a/playout/tests/liquidsoap/entrypoint_test.py b/playout/tests/liquidsoap/entrypoint_test.py new file mode 100644 index 000000000..1c2ab9d10 --- /dev/null +++ b/playout/tests/liquidsoap/entrypoint_test.py @@ -0,0 +1,43 @@ +from pathlib import Path +from unittest import mock + +import pytest + +from libretime_playout.config import Config +from libretime_playout.liquidsoap.entrypoint import generate_entrypoint +from libretime_playout.liquidsoap.models import Info, StreamPreferences + +from ..fixtures import entrypoint_1_1_snapshot, entrypoint_1_4_snapshot + + +@pytest.mark.parametrize( + "version, expected", + [ + pytest.param((1, 1, 1), entrypoint_1_1_snapshot, id="snapshot_1.1"), + pytest.param((1, 4, 4), entrypoint_1_4_snapshot, id="snapshot_1.4"), + ], +) +def test_generate_entrypoint(tmp_path: Path, config: Config, version, expected): + entrypoint_filepath = tmp_path / "radio.liq" + + with mock.patch( + "libretime_playout.liquidsoap.entrypoint.here", + Path("/fake"), + ): + generate_entrypoint( + entrypoint_filepath, + log_filepath=Path("/var/log/radio.log"), + config=config, + preferences=StreamPreferences( + input_fade_transition=0.0, + message_format=0, + message_offline="LibreTime - offline", + ), + info=Info( + station_name="LibreTime", + ), + version=version, + ) + + found = entrypoint_filepath.read_text(encoding="utf-8") + assert found == expected