- Auto-select the network adapter when only one is found (configurable via auto_select_single; asked on first run)
This commit is contained in:
@@ -18,7 +18,7 @@ from .update_check import check_for_update
|
|||||||
from .network import list_adapters, set_static_ip, revert_to_dhcp, get_current_ipv4
|
from .network import list_adapters, set_static_ip, revert_to_dhcp, get_current_ipv4
|
||||||
|
|
||||||
|
|
||||||
def _pick_adapter(console: Console) -> dict | None:
|
def _pick_adapter(console: Console, auto_single: bool = True) -> dict | None:
|
||||||
adapters = list_adapters()
|
adapters = list_adapters()
|
||||||
if not adapters:
|
if not adapters:
|
||||||
console.print(f"[red]{t('no_adapters')}[/]")
|
console.print(f"[red]{t('no_adapters')}[/]")
|
||||||
@@ -29,6 +29,10 @@ def _pick_adapter(console: Console) -> dict | None:
|
|||||||
ip = a.get("IPv4") or "—"
|
ip = a.get("IPv4") or "—"
|
||||||
console.print(f" {i}) [{a['Status']:<12}] {a['Name']} ({a['Description']}) {ip}")
|
console.print(f" {i}) [{a['Status']:<12}] {a['Name']} ({a['Description']}) {ip}")
|
||||||
|
|
||||||
|
if auto_single and len(adapters) == 1:
|
||||||
|
console.print(f"[green]{t('only_adapter', name=adapters[0]['Name'])}[/]")
|
||||||
|
return adapters[0]
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
s = Prompt.ask(t("select_adapter")).strip()
|
s = Prompt.ask(t("select_adapter")).strip()
|
||||||
if s.isdigit() and 1 <= int(s) <= len(adapters):
|
if s.isdigit() and 1 <= int(s) <= len(adapters):
|
||||||
@@ -80,7 +84,7 @@ def main() -> None:
|
|||||||
console.print(title)
|
console.print(title)
|
||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
nic = _pick_adapter(console)
|
nic = _pick_adapter(console, cfg_data.get("auto_select_single", True))
|
||||||
if not nic:
|
if not nic:
|
||||||
input(t("press_enter")); return
|
input(t("press_enter")); return
|
||||||
|
|
||||||
|
|||||||
+37
-10
@@ -19,16 +19,25 @@ CONFIG_HEADER = """\
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# netswitch configuration
|
# netswitch configuration
|
||||||
#
|
#
|
||||||
# To change the interface language, edit the 'language' value below.
|
# language : interface language. Valid: en, ru
|
||||||
# Valid values: en, ru
|
# auto_select_single : auto-pick the network adapter when only one is found,
|
||||||
|
# without asking (yes/no).
|
||||||
#
|
#
|
||||||
# Чтобы сменить язык интерфейса, измените значение 'language' ниже.
|
# language : язык интерфейса. Допустимо: en, ru
|
||||||
# Допустимые значения: en, ru
|
# auto_select_single : автоматически выбирать сетевой адаптер, если он
|
||||||
|
# единственный, не спрашивая (yes/no).
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _to_bool(s: str, default: bool) -> bool:
|
||||||
|
s = (s or "").strip().lower()
|
||||||
|
if s in ("yes", "true", "y", "1", "on"): return True
|
||||||
|
if s in ("no", "false", "n", "0", "off"): return False
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
def app_dir() -> Path:
|
def app_dir() -> Path:
|
||||||
"""Directory holding the running executable (or source folder when run via python)."""
|
"""Directory holding the running executable (or source folder when run via python)."""
|
||||||
if getattr(sys, "frozen", False):
|
if getattr(sys, "frozen", False):
|
||||||
@@ -57,10 +66,26 @@ def _ask_language() -> str:
|
|||||||
print("Please enter 1 or 2 / Введите 1 или 2")
|
print("Please enter 1 or 2 / Введите 1 или 2")
|
||||||
|
|
||||||
|
|
||||||
def _write_config(lang: str) -> None:
|
def _ask_auto_select() -> bool:
|
||||||
|
"""First-run prompt — auto-select a lone adapter? Bilingual stdin."""
|
||||||
|
print()
|
||||||
|
print("Auto-select the network adapter when only one is found? (y/n)")
|
||||||
|
print("Автовыбор сетевого адаптера, если он единственный? (y/n)")
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
c = input("> ").strip().lower()
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
return True
|
||||||
|
if c in ("y", "yes", "д", "да", "1"): return True
|
||||||
|
if c in ("n", "no", "н", "нет", "0"): return False
|
||||||
|
print("y / n")
|
||||||
|
|
||||||
|
|
||||||
|
def _write_config(lang: str, auto_select: bool) -> None:
|
||||||
path = config_path()
|
path = config_path()
|
||||||
cp = configparser.ConfigParser()
|
cp = configparser.ConfigParser()
|
||||||
cp["General"] = {"language": lang}
|
cp["General"] = {"language": lang,
|
||||||
|
"auto_select_single": "yes" if auto_select else "no"}
|
||||||
with path.open("w", encoding="utf-8") as f:
|
with path.open("w", encoding="utf-8") as f:
|
||||||
f.write(CONFIG_HEADER)
|
f.write(CONFIG_HEADER)
|
||||||
cp.write(f)
|
cp.write(f)
|
||||||
@@ -70,19 +95,21 @@ def load_config() -> dict:
|
|||||||
path = config_path()
|
path = config_path()
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
lang = _ask_language()
|
lang = _ask_language()
|
||||||
|
auto = _ask_auto_select()
|
||||||
try:
|
try:
|
||||||
_write_config(lang)
|
_write_config(lang, auto)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
return {"language": lang}
|
return {"language": lang, "auto_select_single": auto}
|
||||||
|
|
||||||
cp = configparser.ConfigParser()
|
cp = configparser.ConfigParser()
|
||||||
try:
|
try:
|
||||||
cp.read(path, encoding="utf-8")
|
cp.read(path, encoding="utf-8")
|
||||||
except (configparser.Error, OSError):
|
except (configparser.Error, OSError):
|
||||||
return {"language": DEFAULT_LANG}
|
return {"language": DEFAULT_LANG, "auto_select_single": True}
|
||||||
|
|
||||||
lang = (cp.get("General", "language", fallback=DEFAULT_LANG) or DEFAULT_LANG).strip().lower()
|
lang = (cp.get("General", "language", fallback=DEFAULT_LANG) or DEFAULT_LANG).strip().lower()
|
||||||
if lang not in SUPPORTED_LANGS:
|
if lang not in SUPPORTED_LANGS:
|
||||||
lang = DEFAULT_LANG
|
lang = DEFAULT_LANG
|
||||||
return {"language": lang}
|
auto = _to_bool(cp.get("General", "auto_select_single", fallback="yes"), True)
|
||||||
|
return {"language": lang, "auto_select_single": auto}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ STRINGS: dict[str, dict[str, str]] = {
|
|||||||
"no_adapters": "No physical wired adapters found.",
|
"no_adapters": "No physical wired adapters found.",
|
||||||
"press_enter": "Press Enter to exit",
|
"press_enter": "Press Enter to exit",
|
||||||
"available_adapters": "Available adapters:",
|
"available_adapters": "Available adapters:",
|
||||||
|
"only_adapter": "Only one adapter, auto-selected: {name}",
|
||||||
"select_adapter": "Select adapter number",
|
"select_adapter": "Select adapter number",
|
||||||
"invalid_selection": "Invalid selection.",
|
"invalid_selection": "Invalid selection.",
|
||||||
"selected": "Selected: {name}",
|
"selected": "Selected: {name}",
|
||||||
@@ -40,6 +41,7 @@ STRINGS: dict[str, dict[str, str]] = {
|
|||||||
"no_adapters": "Подходящие проводные адаптеры не найдены.",
|
"no_adapters": "Подходящие проводные адаптеры не найдены.",
|
||||||
"press_enter": "Нажмите Enter для выхода",
|
"press_enter": "Нажмите Enter для выхода",
|
||||||
"available_adapters": "Доступные адаптеры:",
|
"available_adapters": "Доступные адаптеры:",
|
||||||
|
"only_adapter": "Адаптер один, выбран автоматически: {name}",
|
||||||
"select_adapter": "Введите номер адаптера",
|
"select_adapter": "Введите номер адаптера",
|
||||||
"invalid_selection": "Неверный выбор.",
|
"invalid_selection": "Неверный выбор.",
|
||||||
"selected": "Выбрано: {name}",
|
"selected": "Выбрано: {name}",
|
||||||
|
|||||||
Reference in New Issue
Block a user