Skip to content

Commit f0a761a

Browse files
committed
Fix config key mapping for saved setups
1 parent 291f4e8 commit f0a761a

3 files changed

Lines changed: 186 additions & 16 deletions

File tree

config_loader.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from __future__ import annotations
2+
3+
from argparse import ArgumentParser, Namespace
4+
from typing import Any, Dict
5+
6+
7+
IGNORED_CONFIG_KEYS = {"platform", "auto_start", "custom_video_pipeline"}
8+
CONFIG_ARG_ALIASES = {"stream_id": "streamid"}
9+
VIDEO_SOURCE_OVERRIDE_ATTRS = (
10+
"test",
11+
"hdmi",
12+
"camlink",
13+
"z1",
14+
"z1passthru",
15+
"apple",
16+
"v4l2",
17+
"libcamera",
18+
"rpicam",
19+
"nvidiacsi",
20+
"pipeline",
21+
"video_pipeline",
22+
"filesrc",
23+
"filesrc2",
24+
"pipein",
25+
"novideo",
26+
)
27+
28+
29+
def _arg_is_default(args: Namespace, parser: ArgumentParser, attr: str) -> bool:
30+
if not hasattr(args, attr):
31+
return False
32+
return getattr(args, attr) == parser.get_default(attr)
33+
34+
35+
def _video_source_has_cli_override(args: Namespace, parser: ArgumentParser) -> bool:
36+
for attr in VIDEO_SOURCE_OVERRIDE_ATTRS:
37+
if hasattr(args, attr) and getattr(args, attr) != parser.get_default(attr):
38+
return True
39+
return False
40+
41+
42+
def _apply_video_source_override(
43+
args: Namespace,
44+
parser: ArgumentParser,
45+
value: Any,
46+
config: Dict[str, Any],
47+
) -> None:
48+
if _video_source_has_cli_override(args, parser):
49+
return
50+
51+
if value == "test" and _arg_is_default(args, parser, "test"):
52+
args.test = True
53+
elif value == "libcamera" and _arg_is_default(args, parser, "libcamera"):
54+
args.libcamera = True
55+
elif value == "v4l2" and _arg_is_default(args, parser, "v4l2"):
56+
args.v4l2 = "/dev/video0"
57+
elif value == "custom" and _arg_is_default(args, parser, "video_pipeline"):
58+
custom_pipeline = config.get("custom_video_pipeline")
59+
if custom_pipeline:
60+
args.video_pipeline = custom_pipeline
61+
62+
63+
def apply_config_overrides(
64+
args: Namespace,
65+
parser: ArgumentParser,
66+
config: Dict[str, Any],
67+
) -> Namespace:
68+
for key, value in config.items():
69+
if key in IGNORED_CONFIG_KEYS:
70+
continue
71+
72+
if key == "audio_enabled":
73+
if value is False and _arg_is_default(args, parser, "noaudio"):
74+
args.noaudio = True
75+
continue
76+
77+
if key == "video_source":
78+
_apply_video_source_override(args, parser, value, config)
79+
continue
80+
81+
target_key = CONFIG_ARG_ALIASES.get(key, key)
82+
if _arg_is_default(args, parser, target_key):
83+
setattr(args, target_key, value)
84+
85+
return args

publish.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from pathlib import Path
2525
from typing import Dict, Any, Optional, Tuple, Set, List
2626
from functools import lru_cache
27+
from config_loader import apply_config_overrides
2728
try:
2829
import hashlib
2930
from urllib.parse import urlparse, urlencode
@@ -12271,22 +12272,7 @@ async def main():
1227112272
config = json.load(f)
1227212273

1227312274
# Override args with config values (but command line args take precedence)
12274-
for key, value in config.items():
12275-
if hasattr(args, key) and getattr(args, key) == parser.get_default(key):
12276-
# Only override if the current value is the default
12277-
if key == 'audio_enabled' and value is False:
12278-
setattr(args, 'noaudio', True)
12279-
elif key == 'video_source':
12280-
if value == 'test':
12281-
setattr(args, 'test', True)
12282-
elif value == 'libcamera':
12283-
setattr(args, 'libcamera', True)
12284-
elif value == 'v4l2':
12285-
setattr(args, 'v4l2', '/dev/video0')
12286-
elif value == 'custom' and 'custom_video_pipeline' in config:
12287-
setattr(args, 'video_pipeline', config['custom_video_pipeline'])
12288-
elif key != 'platform' and key != 'auto_start' and key != 'audio_enabled' and key != 'video_source' and key != 'custom_video_pipeline':
12289-
setattr(args, key, value)
12275+
apply_config_overrides(args, parser, config)
1229012276

1229112277
print(f"Loaded configuration from: {config_path}")
1229212278
except Exception as e:

tests/test_config_loader.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import argparse
2+
import unittest
3+
4+
from config_loader import apply_config_overrides
5+
6+
7+
def build_parser():
8+
parser = argparse.ArgumentParser()
9+
parser.add_argument("--streamid", default="cli-default")
10+
parser.add_argument("--bitrate", type=int, default=2500)
11+
parser.add_argument("--test", action="store_true")
12+
parser.add_argument("--hdmi", action="store_true")
13+
parser.add_argument("--camlink", action="store_true")
14+
parser.add_argument("--z1", action="store_true")
15+
parser.add_argument("--z1passthru", action="store_true")
16+
parser.add_argument("--apple", default=None)
17+
parser.add_argument("--v4l2", default=None)
18+
parser.add_argument("--libcamera", action="store_true")
19+
parser.add_argument("--rpicam", action="store_true")
20+
parser.add_argument("--nvidiacsi", action="store_true")
21+
parser.add_argument("--pipeline", default=None)
22+
parser.add_argument("--video-pipeline", dest="video_pipeline", default=None)
23+
parser.add_argument("--filesrc", default=None)
24+
parser.add_argument("--filesrc2", default=None)
25+
parser.add_argument("--pipein", default=None)
26+
parser.add_argument("--novideo", action="store_true")
27+
parser.add_argument("--noaudio", action="store_true")
28+
return parser
29+
30+
31+
class TestConfigLoader(unittest.TestCase):
32+
def test_installer_config_maps_stream_id_and_test_source(self):
33+
parser = build_parser()
34+
args = parser.parse_args([])
35+
36+
apply_config_overrides(
37+
args,
38+
parser,
39+
{
40+
"stream_id": "config-stream",
41+
"bitrate": 1800,
42+
"video_source": "test",
43+
"audio_enabled": True,
44+
},
45+
)
46+
47+
self.assertEqual(args.streamid, "config-stream")
48+
self.assertEqual(args.bitrate, 1800)
49+
self.assertTrue(args.test)
50+
self.assertIsNone(args.v4l2)
51+
self.assertFalse(args.noaudio)
52+
53+
def test_custom_video_source_uses_custom_pipeline(self):
54+
parser = build_parser()
55+
args = parser.parse_args([])
56+
57+
apply_config_overrides(
58+
args,
59+
parser,
60+
{
61+
"video_source": "custom",
62+
"custom_video_pipeline": "videotestsrc pattern=ball",
63+
},
64+
)
65+
66+
self.assertEqual(args.video_pipeline, "videotestsrc pattern=ball")
67+
68+
def test_config_video_source_does_not_override_explicit_cli_source(self):
69+
parser = build_parser()
70+
args = parser.parse_args(["--hdmi"])
71+
72+
apply_config_overrides(
73+
args,
74+
parser,
75+
{
76+
"video_source": "test",
77+
},
78+
)
79+
80+
self.assertTrue(args.hdmi)
81+
self.assertFalse(args.test)
82+
83+
def test_audio_enabled_false_sets_noaudio_when_not_explicitly_set(self):
84+
parser = build_parser()
85+
args = parser.parse_args([])
86+
87+
apply_config_overrides(
88+
args,
89+
parser,
90+
{
91+
"audio_enabled": False,
92+
},
93+
)
94+
95+
self.assertTrue(args.noaudio)
96+
97+
98+
if __name__ == "__main__":
99+
unittest.main()

0 commit comments

Comments
 (0)