feat(playout): build liquidsoap entrypoint with stream config
This commit is contained in:
parent
d9920a1196
commit
b9368d1b7b
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }}"
|
|
@ -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",
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
Loading…
Reference in New Issue