3 Commits

Author SHA1 Message Date
engel 979df127a6 Release 1.2.1: auto-select single NIC
Release / build (push) Has been cancelled
- Auto-select the network adapter when only one is found (configurable via auto_select_single; asked on first run)
2026-06-03 17:55:52 +03:00
engel 876b2c72bc chore: cut GitHub, make netswitch Gitea-only
- relink README/CHANGELOG/pyproject/SECURITY to git.engelgardt23.ru
- update-check + badges point to Gitea; rename GITHUB_REPO -> REPO
- port CI to .gitea/workflows (self-contained, publishes Gitea release)
- remove .github (workflow + issue templates); drop made-by lines
2026-06-01 12:58:03 +03:00
engel 6a99bd9925 chore: switch update-check and release URLs to self-hosted Forgejo
GitHub-репо заморожены; релизы теперь на git.engelgardt23.ru.
2026-05-28 07:14:46 +00:00
16 changed files with 108 additions and 153 deletions
@@ -8,24 +8,30 @@ on:
permissions: permissions:
contents: write contents: write
# Self-contained: no external (GitHub-hosted) actions. Runs on a self-hosted
# Windows runner (label `windows`) that already has Python 3.12 on PATH.
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: windows
steps: steps:
- uses: actions/checkout@v4 - name: Checkout repository at tag
shell: pwsh
- name: Set up Python env:
uses: actions/setup-python@v5 TOKEN: ${{ github.token }}
with: run: |
python-version: '3.12' $base = "${{ github.server_url }}" -replace '^https://', ''
$url = "https://oauth2:$env:TOKEN@$base/${{ github.repository }}.git"
git clone --depth 1 --branch "$env:GITHUB_REF_NAME" $url .
- name: Install build dependencies - name: Install build dependencies
run: python -m pip install --upgrade pip pyinstaller rich run: python -m pip install --upgrade pip pyinstaller rich
- name: Resolve version from tag - name: Resolve version from tag
id: ver id: ver
shell: bash shell: pwsh
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" run: |
$v = "$env:GITHUB_REF_NAME" -replace '^v', ''
"version=$v" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Build executable - name: Build executable
run: python -m PyInstaller --onefile --uac-admin --console --name netswitch --icon assets/icon.ico --paths src netswitch-launcher.py run: python -m PyInstaller --onefile --uac-admin --console --name netswitch --icon assets/icon.ico --paths src netswitch-launcher.py
@@ -39,7 +45,6 @@ jobs:
Copy-Item dist/netswitch.exe $folder/ Copy-Item dist/netswitch.exe $folder/
@" @"
netswitch v$ver - portable edition netswitch v$ver - portable edition
made by engelgardt
Quickly set a Windows network adapter to a static IP or back to DHCP. Quickly set a Windows network adapter to a static IP or back to DHCP.
@@ -66,10 +71,19 @@ jobs:
"$hash $zip" | Out-File -FilePath "$zip.sha256" -Encoding ASCII -NoNewline "$hash $zip" | Out-File -FilePath "$zip.sha256" -Encoding ASCII -NoNewline
Get-Content "$zip.sha256" Get-Content "$zip.sha256"
- name: Create release - name: Publish Gitea release
uses: softprops/action-gh-release@v2 shell: pwsh
with: env:
files: | TOKEN: ${{ github.token }}
netswitch-portable-v${{ steps.ver.outputs.version }}.zip run: |
netswitch-portable-v${{ steps.ver.outputs.version }}.zip.sha256 $ver = '${{ steps.ver.outputs.version }}'
generate_release_notes: true $tag = "v$ver"
$api = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
$hdr = @{ Authorization = "token $env:TOKEN" }
$body = @{ tag_name = $tag; name = $tag; draft = $false; prerelease = $false } | ConvertTo-Json
$rel = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $hdr -ContentType 'application/json' -Body $body
$rid = $rel.id
foreach ($f in @("netswitch-portable-v$ver.zip", "netswitch-portable-v$ver.zip.sha256")) {
curl.exe -s -H "Authorization: token $env:TOKEN" -F "attachment=@$f" "$api/releases/$rid/assets?name=$f" | Out-Null
Write-Host "uploaded $f"
}
-55
View File
@@ -1,55 +0,0 @@
name: Bug report
description: Something doesn't work as expected
labels: ["bug"]
body:
- type: input
id: version
attributes:
label: Version
description: Visible in the startup banner.
placeholder: v1.0.0
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1. ...
2. ...
3. ...
validations:
required: true
- type: textarea
id: expected
attributes:
label: What you expected to happen
validations:
required: true
- type: textarea
id: actual
attributes:
label: What actually happened
description: Paste any error output verbatim. Screenshots are welcome.
validations:
required: true
- type: input
id: os
attributes:
label: Windows version
placeholder: e.g. Windows 11 24H2
- type: input
id: adapter
attributes:
label: Adapter (if relevant)
placeholder: e.g. Realtek USB GbE Family Controller
- type: textarea
id: extra
attributes:
label: Anything else?
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability
url: https://github.com/Engelgardt23/netswitch/security/advisories/new
about: Please report security issues privately via GitHub Security Advisories — not as a public issue.
@@ -1,23 +0,0 @@
name: Feature request
description: Suggest a new feature or an improvement
labels: ["enhancement"]
body:
- type: textarea
id: motivation
attributes:
label: What's the use case?
description: What are you trying to do, and why is the current behavior not enough?
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
+1 -1
View File
@@ -13,7 +13,7 @@ builds/
# Legacy staging folders (kept for compatibility with old checkouts) # Legacy staging folders (kept for compatibility with old checkouts)
portable-v*/ portable-v*/
# Stray standalone exe (we never commit binaries — they live in GitHub releases) # Stray standalone exe (we never commit binaries — they live in Gitea releases)
*.exe *.exe
# Local backup of release archives (kept locally for history, not in repo) # Local backup of release archives (kept locally for history, not in repo)
+10 -10
View File
@@ -10,7 +10,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
### Changed ### Changed
- **Rewrote netswitch in Python** (was PowerShell + ps2exe). The single-file `.ps1` script is gone, replaced by a small `netswitch/` package (`app.py`, `config.py`, `i18n.py`, `network.py`, `platform_win.py`, `update_check.py`) that mirrors the layout used by `dhcpsrv`. CI now builds via PyInstaller instead of ps2exe. - **Rewrote netswitch in Python** (was PowerShell + ps2exe). The single-file `.ps1` script is gone, replaced by a small `netswitch/` package (`app.py`, `config.py`, `i18n.py`, `network.py`, `platform_win.py`, `update_check.py`) that mirrors the layout used by `dhcpsrv`. CI now builds via PyInstaller instead of ps2exe.
- Output is now a Rich-styled console (coloured banner, current-config table) instead of plain `Write-Host`. - Output is now a Rich-styled console (coloured banner, current-config table) instead of plain `Write-Host`.
- The `Update available (vX.Y.Z)` notice in the header is a clickable terminal hyperlink to the GitHub releases page (OSC 8). Modern terminals render it as a link; older consoles show plain text. - The `Update available (vX.Y.Z)` notice in the header is a clickable terminal hyperlink to the releases page (OSC 8). Modern terminals render it as a link; older consoles show plain text.
### Removed ### Removed
- `src/netswitch.ps1` and the ps2exe build step. If you specifically need a tiny PowerShell version, check out tag `v1.1.0`. - `src/netswitch.ps1` and the ps2exe build step. If you specifically need a tiny PowerShell version, check out tag `v1.1.0`.
@@ -35,19 +35,19 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
## [1.0.0] - 2026-05-16 ## [1.0.0] - 2026-05-16
### Added ### Added
- First public release on GitHub. - First public release.
- Portable `.exe` (~30 KB) built from PowerShell via ps2exe. - Portable `.exe` (~30 KB) built from PowerShell via ps2exe.
- Self-elevation through UAC. - Self-elevation through UAC.
- Physical wired NIC filter — Wi-Fi, VPN, virtual, Hyper-V, VMware, VirtualBox, TAP/TUN, WireGuard, OpenVPN, Tailscale, ZeroTier, Bluetooth, Loopback and WAN Miniport adapters are hidden from the picker. - Physical wired NIC filter — Wi-Fi, VPN, virtual, Hyper-V, VMware, VirtualBox, TAP/TUN, WireGuard, OpenVPN, Tailscale, ZeroTier, Bluetooth, Loopback and WAN Miniport adapters are hidden from the picker.
- Two modes: **Static** (default `10.10.10.1/24`, optional gateway) and **DHCP**. - Two modes: **Static** (default `10.10.10.1/24`, optional gateway) and **DHCP**.
- Current IPv4 configuration is printed after the change. - Current IPv4 configuration is printed after the change.
- Auto-update check on startup: polls GitHub `/releases/latest` with a 3-second timeout and offers to open the download page if a newer version exists. Silent on offline / API errors. - Auto-update check on startup: polls the Gitea instance `/releases/latest` with a 3-second timeout and offers to open the download page if a newer version exists. Silent on offline / API errors.
- MIT licensed. - MIT licensed.
[Unreleased]: https://github.com/Engelgardt23/netswitch/compare/v1.2.0...HEAD [Unreleased]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.2.0...HEAD
[1.2.0]: https://github.com/Engelgardt23/netswitch/compare/v1.1.0...v1.2.0 [1.2.0]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/Engelgardt23/netswitch/compare/v1.0.3...v1.1.0 [1.1.0]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.0.3...v1.1.0
[1.0.3]: https://github.com/Engelgardt23/netswitch/compare/v1.0.2...v1.0.3 [1.0.3]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.0.2...v1.0.3
[1.0.2]: https://github.com/Engelgardt23/netswitch/compare/v1.0.1...v1.0.2 [1.0.2]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/Engelgardt23/netswitch/compare/v1.0.0...v1.0.1 [1.0.1]: https://git.engelgardt23.ru/engel/netswitch/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/Engelgardt23/netswitch/releases/tag/v1.0.0 [1.0.0]: https://git.engelgardt23.ru/engel/netswitch/releases/tag/v1.0.0
+5 -6
View File
@@ -6,9 +6,8 @@
``` ```
netswitch/ netswitch/
├── .github/ ├── .gitea/
── workflows/release.yml ← CI: tag-driven build + GitHub Release ── workflows/release.yml ← CI: tag-driven build + Gitea Release
│ └── ISSUE_TEMPLATE/ ← bug / feature / security routing
├── src/ ├── src/
│ └── netswitch.ps1 ← the whole tool (~150 lines) │ └── netswitch.ps1 ← the whole tool (~150 lines)
├── CHANGELOG.md ← Keep a Changelog format, newest first ├── CHANGELOG.md ← Keep a Changelog format, newest first
@@ -43,16 +42,16 @@ Invoke-ps2exe -inputFile src/netswitch.ps1 -outputFile netswitch.exe `
4. Tag: `git tag vX.Y.Z`. 4. Tag: `git tag vX.Y.Z`.
5. Push: `git push && git push --tags`. 5. Push: `git push && git push --tags`.
GitHub Actions picks up the tag, builds the exe via ps2exe, writes the SHA-256, and creates the GitHub Release with the zip attached. Gitea Actions picks up the tag, builds the exe, writes the SHA-256, and creates the Gitea Release with the zip attached.
## Where features go ## Where features go
The whole tool is a single PowerShell file with these sections (in order): The whole tool is a single PowerShell file with these sections (in order):
1. `$NetswitchVersion` / `$GithubRepo` — top of file. 1. `$NetswitchVersion` / `$Repo` — top of file.
2. **Self-elevate** block — UAC if non-admin. 2. **Self-elevate** block — UAC if non-admin.
3. **Banner** — Write-Host title. 3. **Banner** — Write-Host title.
4. **`Test-NetswitchUpdate`** — GitHub /releases/latest poll. 4. **`Test-NetswitchUpdate`** — Gitea /releases/latest poll.
5. **Adapter filter + picker**`$skipDescriptionPattern`, `$skipMediaTypes`, `Get-NetAdapter | Where-Object {...}`. 5. **Adapter filter + picker**`$skipDescriptionPattern`, `$skipMediaTypes`, `Get-NetAdapter | Where-Object {...}`.
6. **Mode prompt** — Static / DHCP. 6. **Mode prompt** — Static / DHCP.
7. **Static branch**`netsh interface ipv4 set address ... static ...`. 7. **Static branch**`netsh interface ipv4 set address ... static ...`.
+3 -5
View File
@@ -1,6 +1,6 @@
# netswitch # netswitch
[![Latest release](https://img.shields.io/github/v/release/Engelgardt23/netswitch)](https://github.com/Engelgardt23/netswitch/releases/latest) [![Latest release](https://img.shields.io/gitea/v/release/engel/netswitch?gitea_url=https%3A%2F%2Fgit.engelgardt23.ru&label=release)](https://git.engelgardt23.ru/engel/netswitch/releases/latest)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
🇺🇸 English | [🇷🇺 Русский](README.ru.md) 🇺🇸 English | [🇷🇺 Русский](README.ru.md)
@@ -9,13 +9,11 @@ A tiny portable tool to flip a Windows network adapter between a **static IP** a
Built for the recurring engineer chore of "give my laptop NIC 10.10.10.1 so I can talk to a server's BMC" and "now put it back on DHCP so I can have internet again." Built for the recurring engineer chore of "give my laptop NIC 10.10.10.1 so I can talk to a server's BMC" and "now put it back on DHCP so I can have internet again."
> **Made by engelgardt.**
--- ---
## Download ## Download
Grab the latest release: [**releases page**](https://github.com/Engelgardt23/netswitch/releases/latest). Grab the latest release: [**releases page**](https://git.engelgardt23.ru/engel/netswitch/releases/latest).
The asset is `netswitch-portable-vX.Y.Z.zip` (~30 KB). The asset is `netswitch-portable-vX.Y.Z.zip` (~30 KB).
## Run ## Run
@@ -34,7 +32,7 @@ Only real, wired physical adapters appear in the picker. Wireless, VPN, virtual,
## Update check ## Update check
On every launch the tool calls GitHub's `/releases/latest` (3-second timeout). If a newer version is available, it prints a yellow notice and offers to open the download page in your browser. If you're offline, it stays silent. On every launch the tool calls the Gitea instance's `/releases/latest` (3-second timeout). If a newer version is available, it prints a yellow notice and offers to open the download page in your browser. If you're offline, it stays silent.
## Build from source ## Build from source
+3 -5
View File
@@ -1,6 +1,6 @@
# netswitch # netswitch
[![Последний релиз](https://img.shields.io/github/v/release/Engelgardt23/netswitch)](https://github.com/Engelgardt23/netswitch/releases/latest) [![Последний релиз](https://img.shields.io/gitea/v/release/engel/netswitch?gitea_url=https%3A%2F%2Fgit.engelgardt23.ru&label=release)](https://git.engelgardt23.ru/engel/netswitch/releases/latest)
[![Лицензия: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Лицензия: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[🇺🇸 English](README.md) | 🇷🇺 Русский [🇺🇸 English](README.md) | 🇷🇺 Русский
@@ -9,13 +9,11 @@
Решает регулярную задачу инженера: «дай моему ноуту 10.10.10.1, чтобы я мог достучаться до BMC сервера», а потом «верни обратно на DHCP, чтобы был интернет». Решает регулярную задачу инженера: «дай моему ноуту 10.10.10.1, чтобы я мог достучаться до BMC сервера», а потом «верни обратно на DHCP, чтобы был интернет».
> **Автор: engelgardt.**
--- ---
## Скачать ## Скачать
Последний релиз: [**страница релизов**](https://github.com/Engelgardt23/netswitch/releases/latest). Последний релиз: [**страница релизов**](https://git.engelgardt23.ru/engel/netswitch/releases/latest).
Архив `netswitch-portable-vX.Y.Z.zip` (~30 КБ). Архив `netswitch-portable-vX.Y.Z.zip` (~30 КБ).
## Запуск ## Запуск
@@ -35,7 +33,7 @@
## Проверка обновлений ## Проверка обновлений
При каждом запуске тулза стучится в GitHub `/releases/latest` (таймаут 3 секунды). Если есть свежая версия — справа в шапке появится тусклая надпись `доступно обновление (vX.Y.Z)`. Если интернета нет — молчит. При каждом запуске тулза стучится в Gitea `/releases/latest` (таймаут 3 секунды). Если есть свежая версия — справа в шапке появится тусклая надпись `доступно обновление (vX.Y.Z)`. Если интернета нет — молчит.
## Конфиг ## Конфиг
+2 -4
View File
@@ -6,16 +6,14 @@ vulnerability reports are very welcome.
## Supported versions ## Supported versions
Only the latest tagged release on GitHub is supported. Older versions will not Only the latest tagged release is supported. Older versions will not
get fixes; please upgrade first. get fixes; please upgrade first.
## How to report a vulnerability ## How to report a vulnerability
**Please do not open a public issue** for security-sensitive findings. **Please do not open a public issue** for security-sensitive findings.
Use GitHub's private security advisories: go to the Report privately by email to the maintainer at engelgardt2024@gmail.com.
[Security tab](../../security/advisories/new) of this repo and click
"Report a vulnerability". GitHub will route it privately.
Please include: Please include:
- The version you tested (the startup banner is enough). - The version you tested (the startup banner is enough).
+2 -2
View File
@@ -13,8 +13,8 @@ dependencies = ["rich>=13"]
dynamic = ["version"] dynamic = ["version"]
[project.urls] [project.urls]
Homepage = "https://github.com/Engelgardt23/netswitch" Homepage = "https://git.engelgardt23.ru/engel/netswitch"
Issues = "https://github.com/Engelgardt23/netswitch/issues" Issues = "https://git.engelgardt23.ru/engel/netswitch/issues"
[project.scripts] [project.scripts]
netswitch = "netswitch.app:main" netswitch = "netswitch.app:main"
+2 -3
View File
@@ -1,10 +1,9 @@
""" """
netswitch - portable Windows NIC IP / DHCP toggle. netswitch - portable Windows NIC IP / DHCP toggle.
made by engelgardt
The single source of truth for the project version. Bump this before tagging The single source of truth for the project version. Bump this before tagging
a release; CI reads the tag, the code reads this constant. a release; CI reads the tag, the code reads this constant.
""" """
__version__ = "1.2.0" __version__ = "1.2.1"
GITHUB_REPO = "Engelgardt23/netswitch" REPO = "engel/netswitch" # self-hosted Gitea (git.engelgardt23.ru)
+8 -4
View File
@@ -10,7 +10,7 @@ from rich.console import Console
from rich.prompt import Prompt from rich.prompt import Prompt
from rich.table import Table from rich.table import Table
from . import __version__, GITHUB_REPO from . import __version__, REPO
from .platform_win import enable_vt, require_admin from .platform_win import enable_vt, require_admin
from .config import load_config from .config import load_config
from .i18n import set_language, t from .i18n import set_language, t
@@ -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):
@@ -69,7 +73,7 @@ def main() -> None:
title = f"[bold cyan]netswitch v{__version__}[/] {t('tagline')}" title = f"[bold cyan]netswitch v{__version__}[/] {t('tagline')}"
latest = check_for_update() latest = check_for_update()
if latest: if latest:
release_url = f"https://github.com/{GITHUB_REPO}/releases/latest" release_url = f"https://git.engelgardt23.ru/{REPO}/releases/latest"
notice = t("update_available", tag=latest) notice = t("update_available", tag=latest)
header = Table.grid(expand=True) header = Table.grid(expand=True)
header.add_column(justify="left", ratio=1) header.add_column(justify="left", ratio=1)
@@ -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
View File
@@ -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}
+2
View File
@@ -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}",
+2 -3
View File
@@ -5,7 +5,7 @@ from __future__ import annotations
import json import json
import urllib.request import urllib.request
from . import __version__, GITHUB_REPO from . import __version__, REPO
def _parse_version(s: str) -> tuple[int, int, int]: def _parse_version(s: str) -> tuple[int, int, int]:
@@ -21,9 +21,8 @@ def _parse_version(s: str) -> tuple[int, int, int]:
def check_for_update() -> str | None: def check_for_update() -> str | None:
try: try:
url = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest" url = f"https://git.engelgardt23.ru/api/v1/repos/{REPO}/releases/latest"
req = urllib.request.Request(url, headers={ req = urllib.request.Request(url, headers={
"Accept": "application/vnd.github+json",
"User-Agent": f"netswitch/{__version__}", "User-Agent": f"netswitch/{__version__}",
}) })
with urllib.request.urlopen(req, timeout=3) as r: with urllib.request.urlopen(req, timeout=3) as r: