fix: apply replay gain preferences on scheduled files (#2945)
### Description
The replay gain preferences are applied in the legacy code, but the
playout code was missing this feature. The replay gain was not applied
when playout fetched the schedules.
37d1a7685e/legacy/application/models/Schedule.php (L881-L886)
This commit is contained in:
parent
37d1a7685e
commit
35d0dec4a8
|
@ -18,12 +18,13 @@ class StreamPreferences(BaseModel):
|
|||
input_fade_transition: float
|
||||
message_format: MessageFormatKind
|
||||
message_offline: str
|
||||
replay_gain_enabled: bool
|
||||
replay_gain_offset: float
|
||||
|
||||
# input_auto_switch_off: bool
|
||||
# input_auto_switch_on: bool
|
||||
# input_main_user: str
|
||||
# input_main_password: str
|
||||
# replay_gain_enabled: bool
|
||||
# replay_gain_offset: float
|
||||
# track_fade_in: float
|
||||
# track_fade_out: float
|
||||
# track_fade_transition: float
|
||||
|
@ -82,6 +83,8 @@ class Preference(models.Model):
|
|||
int(entries.get("stream_label_format") or 0)
|
||||
),
|
||||
message_offline=entries.get("off_air_meta") or "Offline",
|
||||
replay_gain_enabled=entries.get("enable_replay_gain") == "1",
|
||||
replay_gain_offset=float(entries.get("replay_gain_modifier") or 0.0),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -6,6 +6,8 @@ class StreamPreferencesSerializer(serializers.Serializer):
|
|||
input_fade_transition = serializers.FloatField(read_only=True)
|
||||
message_format = serializers.IntegerField(read_only=True)
|
||||
message_offline = serializers.CharField(read_only=True)
|
||||
replay_gain_enabled = serializers.BooleanField(read_only=True)
|
||||
replay_gain_offset = serializers.FloatField(read_only=True)
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
|
|
|
@ -16,6 +16,8 @@ def test_preference_get_stream_preferences(db):
|
|||
"input_fade_transition": 0.0,
|
||||
"message_format": 0,
|
||||
"message_offline": "LibreTime - offline",
|
||||
"replay_gain_enabled": True,
|
||||
"replay_gain_offset": 0.0,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ def test_stream_preferences_get(db, api_client: APIClient):
|
|||
"input_fade_transition": 0.0,
|
||||
"message_format": 0,
|
||||
"message_offline": "LibreTime - offline",
|
||||
"replay_gain_enabled": True,
|
||||
"replay_gain_offset": 0.0,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ class StreamPreferencesView(views.APIView):
|
|||
"input_fade_transition",
|
||||
"message_format",
|
||||
"message_offline",
|
||||
"replay_gain_enabled",
|
||||
"replay_gain_offset",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
@ -7535,10 +7535,19 @@ components:
|
|||
message_offline:
|
||||
type: string
|
||||
readOnly: true
|
||||
replay_gain_enabled:
|
||||
type: boolean
|
||||
readOnly: true
|
||||
replay_gain_offset:
|
||||
type: number
|
||||
format: double
|
||||
readOnly: true
|
||||
required:
|
||||
- input_fade_transition
|
||||
- message_format
|
||||
- message_offline
|
||||
- replay_gain_enabled
|
||||
- replay_gain_offset
|
||||
StreamState:
|
||||
type: object
|
||||
properties:
|
||||
|
|
|
@ -17,6 +17,8 @@ class StreamPreferences(BaseModel):
|
|||
input_fade_transition: float
|
||||
message_format: MessageFormatKind
|
||||
message_offline: str
|
||||
replay_gain_enabled: bool
|
||||
replay_gain_offset: float
|
||||
|
||||
|
||||
class StreamState(BaseModel):
|
||||
|
|
|
@ -64,15 +64,11 @@ def get_schedule(api_client: ApiClient) -> Events:
|
|||
if show["live_enabled"]:
|
||||
show_instance["starts_at"] = event_isoparse(show_instance["starts_at"])
|
||||
show_instance["ends_at"] = event_isoparse(show_instance["ends_at"])
|
||||
generate_live_events(
|
||||
events,
|
||||
show_instance,
|
||||
stream_preferences.input_fade_transition,
|
||||
)
|
||||
generate_live_events(events, show_instance, stream_preferences)
|
||||
|
||||
if item["file"]:
|
||||
file = api_client.get_file(item["file"]).json()
|
||||
generate_file_events(events, item, file, show)
|
||||
generate_file_events(events, item, file, show, stream_preferences)
|
||||
|
||||
elif item["stream"]:
|
||||
webstream = api_client.get_webstream(item["stream"]).json()
|
||||
|
@ -84,9 +80,9 @@ def get_schedule(api_client: ApiClient) -> Events:
|
|||
def generate_live_events(
|
||||
events: Events,
|
||||
show_instance: dict,
|
||||
input_fade_transition: float,
|
||||
stream_preferences: StreamPreferences,
|
||||
):
|
||||
transition = timedelta(seconds=input_fade_transition)
|
||||
transition = timedelta(seconds=stream_preferences.input_fade_transition)
|
||||
|
||||
switch_off = show_instance["ends_at"] - transition
|
||||
kick_out = show_instance["ends_at"]
|
||||
|
@ -118,6 +114,7 @@ def generate_file_events(
|
|||
schedule: dict,
|
||||
file: dict,
|
||||
show: dict,
|
||||
stream_preferences: StreamPreferences,
|
||||
):
|
||||
"""
|
||||
Generate events for a scheduled file.
|
||||
|
@ -143,6 +140,15 @@ def generate_file_events(
|
|||
replay_gain=file["replay_gain"],
|
||||
filesize=file["size"],
|
||||
)
|
||||
|
||||
if event.replay_gain is None:
|
||||
event.replay_gain = 0.0
|
||||
|
||||
if stream_preferences.replay_gain_enabled:
|
||||
event.replay_gain += stream_preferences.replay_gain_offset
|
||||
else:
|
||||
event.replay_gain = None
|
||||
|
||||
insert_event(events, event.start_key, event)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import pytest
|
||||
|
||||
from libretime_playout.config import Config
|
||||
from libretime_playout.liquidsoap.models import StreamPreferences
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -36,3 +37,14 @@ def config():
|
|||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def stream_preferences():
|
||||
return StreamPreferences(
|
||||
input_fade_transition=0.0,
|
||||
message_format=0,
|
||||
message_offline="LibreTime - offline",
|
||||
replay_gain_enabled=True,
|
||||
replay_gain_offset=-3.5,
|
||||
)
|
||||
|
|
|
@ -21,7 +21,12 @@ from .fixtures import TEST_STREAM_CONFIGS, make_config_with_stream
|
|||
"stream_config",
|
||||
TEST_STREAM_CONFIGS,
|
||||
)
|
||||
def test_generate_entrypoint(stream_config: Config, version, snapshot):
|
||||
def test_generate_entrypoint(
|
||||
stream_config: Config,
|
||||
stream_preferences: StreamPreferences,
|
||||
version,
|
||||
snapshot,
|
||||
):
|
||||
with mock.patch(
|
||||
"libretime_playout.liquidsoap.entrypoint.here",
|
||||
Path("/fake"),
|
||||
|
@ -29,11 +34,7 @@ def test_generate_entrypoint(stream_config: Config, version, snapshot):
|
|||
found = generate_entrypoint(
|
||||
log_filepath=Path("/var/log/radio.log"),
|
||||
config=stream_config,
|
||||
preferences=StreamPreferences(
|
||||
input_fade_transition=0.0,
|
||||
message_format=0,
|
||||
message_offline="LibreTime - offline",
|
||||
),
|
||||
preferences=stream_preferences,
|
||||
info=Info(
|
||||
station_name="LibreTime",
|
||||
),
|
||||
|
@ -51,7 +52,11 @@ def test_generate_entrypoint(stream_config: Config, version, snapshot):
|
|||
"stream_config",
|
||||
TEST_STREAM_CONFIGS,
|
||||
)
|
||||
def test_liquidsoap_syntax(tmp_path: Path, stream_config):
|
||||
def test_liquidsoap_syntax(
|
||||
tmp_path: Path,
|
||||
stream_config: Config,
|
||||
stream_preferences: StreamPreferences,
|
||||
):
|
||||
entrypoint_filepath = tmp_path / "radio.liq"
|
||||
log_filepath = tmp_path / "radio.log"
|
||||
|
||||
|
@ -59,11 +64,7 @@ def test_liquidsoap_syntax(tmp_path: Path, stream_config):
|
|||
generate_entrypoint(
|
||||
log_filepath=log_filepath,
|
||||
config=stream_config,
|
||||
preferences=StreamPreferences(
|
||||
input_fade_transition=0.0,
|
||||
message_format=0,
|
||||
message_offline="LibreTime - offline",
|
||||
),
|
||||
preferences=stream_preferences,
|
||||
info=Info(
|
||||
station_name="LibreTime",
|
||||
),
|
||||
|
@ -79,7 +80,10 @@ def test_liquidsoap_syntax(tmp_path: Path, stream_config):
|
|||
LIQ_VERSION >= (2, 0, 0),
|
||||
reason="unsupported liquidsoap >= 2.0.0",
|
||||
)
|
||||
def test_liquidsoap_unsupported_output_aac(tmp_path: Path):
|
||||
def test_liquidsoap_unsupported_output_aac(
|
||||
tmp_path: Path,
|
||||
stream_preferences: StreamPreferences,
|
||||
):
|
||||
entrypoint_filepath = tmp_path / "radio.liq"
|
||||
log_filepath = tmp_path / "radio.log"
|
||||
|
||||
|
@ -98,11 +102,7 @@ def test_liquidsoap_unsupported_output_aac(tmp_path: Path):
|
|||
]
|
||||
}
|
||||
),
|
||||
preferences=StreamPreferences(
|
||||
input_fade_transition=0.0,
|
||||
message_format=0,
|
||||
message_offline="LibreTime - offline",
|
||||
),
|
||||
preferences=stream_preferences,
|
||||
info=Info(
|
||||
station_name="LibreTime",
|
||||
),
|
||||
|
|
|
@ -4,6 +4,7 @@ from datetime import datetime
|
|||
import pytest
|
||||
from libretime_api_client.v2 import ApiClient
|
||||
|
||||
from libretime_playout.liquidsoap.models import StreamPreferences
|
||||
from libretime_playout.player.events import (
|
||||
ActionEvent,
|
||||
EventKind,
|
||||
|
@ -271,13 +272,13 @@ SCHEDULE = [
|
|||
]
|
||||
|
||||
|
||||
def test_generate_live_events():
|
||||
def test_generate_live_events(stream_preferences: StreamPreferences):
|
||||
show_instance_3 = SHOW_INSTANCE_3.copy()
|
||||
show_instance_3["starts_at"] = event_isoparse(show_instance_3["starts_at"])
|
||||
show_instance_3["ends_at"] = event_isoparse(show_instance_3["ends_at"])
|
||||
|
||||
result = {}
|
||||
generate_live_events(result, show_instance_3, 0.0)
|
||||
generate_live_events(result, show_instance_3, stream_preferences)
|
||||
assert result == {
|
||||
"2022-09-05-13-00-00": ActionEvent(
|
||||
start=datetime(2022, 9, 5, 13, 0),
|
||||
|
@ -288,7 +289,8 @@ def test_generate_live_events():
|
|||
}
|
||||
|
||||
result = {}
|
||||
generate_live_events(result, show_instance_3, 2.0)
|
||||
stream_preferences.input_fade_transition = 2.0
|
||||
generate_live_events(result, show_instance_3, stream_preferences)
|
||||
assert result == {
|
||||
"2022-09-05-12-59-58": ActionEvent(
|
||||
start=datetime(2022, 9, 5, 12, 59, 58),
|
||||
|
@ -305,13 +307,13 @@ def test_generate_live_events():
|
|||
}
|
||||
|
||||
|
||||
def test_generate_file_events():
|
||||
def test_generate_file_events(stream_preferences: StreamPreferences):
|
||||
schedule_1 = SCHEDULE_1.copy()
|
||||
schedule_1["starts_at"] = event_isoparse(schedule_1["starts_at"])
|
||||
schedule_1["ends_at"] = event_isoparse(schedule_1["ends_at"])
|
||||
|
||||
result = {}
|
||||
generate_file_events(result, schedule_1, FILE_2, SHOW_1)
|
||||
generate_file_events(result, schedule_1, FILE_2, SHOW_1, stream_preferences)
|
||||
assert result == {
|
||||
"2022-09-05-11-00-00": FileEvent(
|
||||
start=datetime(2022, 9, 5, 11, 0),
|
||||
|
@ -328,7 +330,32 @@ def test_generate_file_events():
|
|||
track_title="My Friend the Forest",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=11.46,
|
||||
replay_gain=11.46 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
)
|
||||
}
|
||||
|
||||
result = {}
|
||||
stream_preferences.replay_gain_enabled = False
|
||||
generate_file_events(result, schedule_1, FILE_2, SHOW_1, stream_preferences)
|
||||
assert result == {
|
||||
"2022-09-05-11-00-00": FileEvent(
|
||||
start=datetime(2022, 9, 5, 11, 0),
|
||||
end=datetime(2022, 9, 5, 11, 5, 2),
|
||||
type=EventKind.FILE,
|
||||
row_id=1,
|
||||
uri=None,
|
||||
id=2,
|
||||
show_name="Show 1",
|
||||
fade_in=500.0,
|
||||
fade_out=500.0,
|
||||
cue_in=13.7008,
|
||||
cue_out=315.845,
|
||||
track_title="My Friend the Forest",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=None,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
)
|
||||
|
@ -398,6 +425,8 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
"input_fade_transition": 2.0,
|
||||
"message_format": 0,
|
||||
"message_offline": "",
|
||||
"replay_gain_enabled": True,
|
||||
"replay_gain_offset": -3.5,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -434,7 +463,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="My Friend the Forest",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=11.46,
|
||||
replay_gain=11.46 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -453,7 +482,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="#2",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=-1.65,
|
||||
replay_gain=-1.65 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -472,7 +501,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="Democracy Now! 2022-09-05 Monday",
|
||||
artist_name="Democracy Now! Audio",
|
||||
mime="audio/mp3",
|
||||
replay_gain=-1.39,
|
||||
replay_gain=-1.39 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -491,7 +520,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="#2",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=-1.65,
|
||||
replay_gain=-1.65 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -546,7 +575,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="All Melody",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=-2.13,
|
||||
replay_gain=-2.13 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -565,7 +594,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="My Friend the Forest",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=11.46,
|
||||
replay_gain=11.46 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -584,7 +613,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="The Dane",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=4.52,
|
||||
replay_gain=4.52 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -615,7 +644,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="My Friend the Forest",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=11.46,
|
||||
replay_gain=11.46 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
@ -634,7 +663,7 @@ def test_get_schedule(schedule, requests_mock, api_client: ApiClient):
|
|||
track_title="#2",
|
||||
artist_name="Nils Frahm",
|
||||
mime="audio/flac",
|
||||
replay_gain=-1.65,
|
||||
replay_gain=-1.65 - 3.5,
|
||||
filesize=10000,
|
||||
file_ready=False,
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue