Compare commits

..

87 Commits

Author SHA1 Message Date
Kirill Sobakin
0379cf5966 Merge pull request #304 from itdoginfo/fix/diagnostic-singbox-config
feat(diagnostic): stringify sb config json
2026-01-24 12:45:33 +03:00
divocatt
cfee6cec9a feat(diagnostic): stringify sb config json 2026-01-23 16:06:54 +02:00
Kirill Sobakin
ad760a78bf Merge pull request #303 from itdoginfo/fix/minor-fixes
Fix/minor fixes
2026-01-23 15:57:24 +03:00
Andrey Petelin
d854caa4cc fix: Disable dnsmasq noresolv when restoring or using default resolvfile; ensure resolvfile is applied 2026-01-23 17:42:05 +05:00
Andrey Petelin
b44274d7f2 fix: mask selector_proxy_links in podkop redaction to hide sensitive proxy selectors 2026-01-23 16:00:34 +05:00
Andrey Petelin
12d8537d90 fix: only print colored timestamp and message when stdout is a terminal 2026-01-23 15:59:26 +05:00
Kirill Sobakin
8e18426a53 Merge pull request #302 from itdoginfo/fix/log_level
fix: set default log_level to "warn" when missing in settings
2026-01-22 19:23:06 +03:00
Andrey Petelin
41a4f67fd0 fix: set default log_level to "warn" when missing in settings 2026-01-22 21:02:15 +05:00
Kirill Sobakin
c30160d8d3 Merge pull request #296 from itdoginfo/firewall-new-mark
New mark and mask
2026-01-22 13:03:36 +03:00
Kirill Sobakin
42f75c3374 fix: new mark 2026-01-22 13:01:36 +03:00
Kirill Sobakin
2cce383b33 Merge pull request #294 from itdoginfo/roblox
Add Roblox to lists
2026-01-21 18:20:06 +03:00
Kirill Sobakin
81963bfbdf feat: roblox 2026-01-21 18:09:12 +03:00
Kirill Sobakin
f3d2fa5a52 Merge pull request #290 from itdoginfo/feat/exclusion
feat: Add 'exclusion' connection type with direct route rule
2026-01-21 17:34:47 +03:00
Andrey Petelin
474f4b197f Update luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-21 19:32:25 +05:00
Andrey Petelin
6083009c80 feat: Add 'exclusion' connection type with direct route rule 2026-01-19 16:10:09 +05:00
Kirill Sobakin
0672c55188 Merge pull request #284 from itdoginfo/fix/firewall
Fix/firewall
2026-01-15 00:39:14 +03:00
Kirill Sobakin
e14a7e7dd1 Merge pull request #286 from itdoginfo/feat/dashboard-selector
Add selector support to dashboard
2026-01-15 00:15:29 +03:00
divocatt
3f7e7cbc4b feat(dashboard): add selector support to dashboard 2026-01-14 21:04:52 +02:00
divocatt
782f08b71b feat(lang): add translations for selector 2026-01-14 20:21:39 +02:00
Andrey Petelin
a40240bb3f fix: use fwmark/mask and bitwise meta mark comparison to correctly match packet marks 2026-01-14 14:09:51 +05:00
Andrey Petelin
1e9a7bffa4 fix: avoid outbound traffic loop by adding NFT_OUTBOUND_MARK (0x90000) and mangle_output return rule (#248) 2026-01-14 10:29:13 +05:00
Andrey Petelin
4448c09c34 fix: replace fakeip mark 0x105 with 0x80000 to avoid conflict with mwan3 (#275) 2026-01-14 10:25:03 +05:00
Kirill Sobakin
af95c0dcd0 Merge pull request #283 from itdoginfo/feat/selector
feat: add selector proxy type support
2026-01-13 13:11:55 +03:00
Andrey Petelin
d2fbff17bf feat: add selector proxy type support 2026-01-09 23:32:58 +05:00
Kirill Sobakin
a73def1f9a Merge pull request #271 from itdoginfo/fix/fully_routed_ips_priority
fix: lower priority of fully_routed_ips relative to routing_excluded_ips
2025-12-21 16:31:22 +03:00
divocat
9976065696 feat: add locales for log level 2025-12-13 18:15:25 +02:00
Andrey Petelin
aa8f2cef41 feat: Add log_level option in LuCI and use configured value for sing-box logging 2025-12-10 17:58:22 +05:00
Andrey Petelin
96f6def701 fix: lower priority of fully_routed_ips relative to routing_excluded_ips 2025-12-10 16:55:23 +05:00
Kirill Sobakin
0152f073b7 Merge pull request #270 from itdoginfo/fix/267-determine-dhcp-ip
Use network_get_ipaddr to obtain LAN listen IP
2025-12-09 16:40:41 +03:00
Andrey Petelin
06ce944e1c fix: add and source network functions, use network_get_ipaddr to obtain LAN listen IP 2025-12-09 15:15:58 +05:00
Kirill Sobakin
64369a93b0 Merge pull request #263 from kjljxybr/main
Translation update for the installation script
2025-12-03 11:48:57 +03:00
Kirill Sobakin
53a3c943f0 Merge pull request #265 from itdoginfo/fix/service_listen_address
Fix/service listen address
2025-12-03 11:46:53 +03:00
Andrey Petelin
7c7e1c6244 fix: take first LAN IP address and strip CIDR suffix 2025-12-03 10:21:51 +05:00
Andrey Petelin
7fc1f39dd6 fix: have service_listen_address option override automatic detection of listening IP address 2025-12-03 09:58:28 +05:00
Artem Kireev
1c4285dfa8 translations 2025-12-02 10:34:38 +03:00
Kirill Sobakin
ea1273e05e Fix: UDP is lost. Double function call 2025-12-01 23:30:33 +03:00
Kirill Sobakin
5fc3c95928 Merge pull request #262 from itdoginfo/feat/hy2
Feat/hy2
2025-12-01 17:44:40 +03:00
divocat
dd3e70153a fix: correct small points 2025-12-01 16:38:26 +02:00
divocat
622e092317 feat: add hy2 validator 2025-11-30 18:35:06 +02:00
Kirill Sobakin
c045f8f224 Add grpc mode example from #259 2025-11-28 00:44:21 +03:00
Kirill Sobakin
b45088dad7 Merge pull request #259 from kokoc26/main
Feat: service_name for gRPC
2025-11-28 00:43:34 +03:00
Andrey Petelin
82345047cb feat: Add Hysteria2 outbound support 2025-11-26 21:04:46 +05:00
Andrey Petelin
0a4ed367bc refactor: add url_get_scheme and simplify url_get_host/url_get_port using parameter expansion 2025-11-26 21:01:33 +05:00
Andrey Petelin
c3f322ae61 Merge branch 'main' into feat/hy2 2025-11-26 17:06:27 +05:00
Kokoc
eb9239696e feat: add support for optional gRPC service name in outbound transport configuration 2025-11-26 14:52:13 +03:00
Kirill Sobakin
5b3421498e Merge pull request #258 from itdoginfo/refactor/dnsmasq
Refactor/dnsmasq
2025-11-26 14:14:02 +03:00
Andrey Petelin
6a48a060e1 refactor: remove sing-box start exit check 2025-11-26 16:01:41 +05:00
Andrey Petelin
14f704fcb8 fix: use echolog for sing-box start failure 2025-11-26 15:47:12 +05:00
Andrey Petelin
ff43f477e9 chore: restore shutdown_correctly logic 2025-11-26 14:14:27 +05:00
Andrey Petelin
576e58fd17 chore: restore start_main and stop_main; have reload call them instead of full start/stop 2025-11-26 13:56:10 +05:00
Andrey Petelin
d72c98a254 chore: clarify and standardize argument type annotations and optional flags 2025-11-26 10:14:06 +05:00
Andrey Petelin
7a497f1e31 fix: reload PODKOP_CONFIG after uci commit to refresh config on shutdown 2025-11-25 17:05:25 +05:00
Andrey Petelin
d52f6e26ae refactor: add configurable DNS/curl timeouts and retries, detect service proxy, and improve connection checks 2025-11-25 17:04:31 +05:00
Andrey Petelin
68c61aed50 refactor: use uci wrappers 2025-11-25 14:10:18 +05:00
Andrey Petelin
626ac981eb refactor: configuring dnsmasq after starting sing-box 2025-11-25 13:53:24 +05:00
Kirill Sobakin
352d10a047 Fix: HY2 links 2025-11-25 11:32:50 +03:00
Kirill Sobakin
031c419ffb Merge pull request #252 from itdoginfo/fix/argument-list-too-long
jq: Argument list too long
2025-11-24 18:13:43 +03:00
Kirill Sobakin
c13fdf5785 HY2 examples 2025-11-24 18:05:40 +03:00
Andrey Petelin
1b7ab606ba refactor: unify source ruleset preparation and list handlers; make ruleset creation idempotent and atomic updates 2025-11-21 20:37:19 +05:00
Andrey Petelin
2bf208ecac fix: import remote plain domain and subnet lists using chunked processing 2025-11-16 13:21:51 +05:00
Andrey Petelin
e256e4bee5 chore: shorten Text List option label by removing the detailed format hint 2025-11-16 09:56:12 +05:00
Andrey Petelin
32c385b309 fix: load large plain domain/subnet lists in chunks; move ruleset logic to rulesets.sh and nft chunker to nft.sh 2025-11-16 09:55:44 +05:00
Kirill Sobakin
56829c74c8 Merge pull request #246 from itdoginfo/fix/listening_address 2025-11-10 12:58:10 +03:00
Andrey Petelin
9d78cd2ce4 style: add missing semicolons to o.depends calls in luci-app-podkop settings.js 2025-11-06 21:20:05 +05:00
Andrey Petelin
d9ce3b361e chore: correct typo "spedifying" to "specifying" in REST API secret comment 2025-11-06 21:18:15 +05:00
divocat
c67aadf267 feat: add yacd_secret_key support for ws 2025-11-06 16:52:08 +02:00
divocat
ac4d7570f3 feat: add translations for new keys 2025-11-06 16:20:35 +02:00
Andrey Petelin
86897fd0af fix: bind mixed proxy and Clash API to service IP (no 0.0.0.0); add YACD WAN toggle and secret key 2025-11-06 16:33:03 +05:00
Andrey Petelin
230ffbce46 feat: Add optional secret for RESTful API to experimental.clash_api config 2025-11-06 16:30:42 +05:00
Kirill Sobakin
dd5ddd1a14 Merge pull request #240 from itdoginfo/fix/long-nft-command
Import large subnet lists in chunks into nft sets
2025-10-30 16:01:14 +03:00
Andrey Petelin
cc947f9734 fix: import large subnet lists in chunks into nft sets 2025-10-30 14:07:12 +05:00
Kirill Sobakin
f8510cd828 Merge pull request #239 from itdoginfo/fix/crlf-clean
BUG: Clearing CRLF from SRS files
2025-10-29 21:15:47 +03:00
Andrey Petelin
23cbe7be4a fix: include filename in log and remove temp file on CRLF-to-LF conversion 2025-10-29 22:11:29 +05:00
Andrey Petelin
f168fb7e31 refactor: fetch remote JSON to temp files and parse ip_cidr into subnets; remove download_to_stream 2025-10-29 21:52:44 +05:00
Andrey Petelin
fe84b3154f fix: convert Windows CRLF line endings to LF for downloaded files 2025-10-29 21:36:46 +05:00
Kirill Sobakin
d09fdc0b95 Merge pull request #235 from itdoginfo/feat/urltest
feat/urltest
2025-10-27 16:07:13 +03:00
divocat
835cd85970 feat: increase timeouts for delays 2s->5s & 5s -> 10s 2025-10-27 14:56:10 +02:00
divocat
8a3b41ec9c Update fe-app-podkop/locales/podkop.ru.po
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-27 14:18:36 +02:00
divocat
10d7617739 fix: run linter 2025-10-27 14:15:19 +02:00
divocat
68010ed5f7 Update luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-27 14:13:31 +02:00
divocat
557e3666eb Update luci-app-podkop/po/ru/podkop.po
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-27 14:13:20 +02:00
Andrey Petelin
01bff8ccfb chore: refine Russian translations for 'URLTest Testing URL' and 'URLTest Tolerance' 2025-10-27 16:21:51 +05:00
divocat
675a6af89c feat: simplify sb check displaying 2025-10-27 13:16:18 +02:00
divocat
f1a6ff3469 feat: add validations & translations 2025-10-27 13:06:33 +02:00
Andrey Petelin
d4b3377d68 feat: add URLTest check interval, tolerance and testing URL options and wire them into outbound config generation 2025-10-27 15:17:20 +05:00
Kirill Sobakin
d2ef640d76 Merge pull request #233 from itdoginfo/feat/add_display_name
feat: replace outbound code with display name
2025-10-27 12:08:04 +03:00
divocat
47457f2c27 feat: replace outbound code with display name 2025-10-26 16:07:28 +02:00
35 changed files with 2594 additions and 936 deletions

View File

@@ -34,6 +34,7 @@ vless://4d21ce62-8723-4c4d-93e3-d586b107aa40@127.0.0.1:51394?type=ws&encryption=
# gRPC # gRPC
vless://974b39e3-f7bf-42b9-933c-16699c635e77@127.0.0.1:15633?type=grpc&encryption=none&serviceName=TunService&authority=&security=none#vless-gRPC-none vless://974b39e3-f7bf-42b9-933c-16699c635e77@127.0.0.1:15633?type=grpc&encryption=none&serviceName=TunService&authority=&security=none#vless-gRPC-none
vless://651e7eca-5152-46f1-baf2-d502e0af7b27@127.0.0.1:28535?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=reality&pbk=nhZ7NiKfcqESa5ZeBFfsq9o18W-OWOAHLln9UmuVXSk&fp=chrome&sni=google.com&sid=11cbaeaa&spx=%2F#vless-gRPC-reality vless://651e7eca-5152-46f1-baf2-d502e0af7b27@127.0.0.1:28535?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=reality&pbk=nhZ7NiKfcqESa5ZeBFfsq9o18W-OWOAHLln9UmuVXSk&fp=chrome&sni=google.com&sid=11cbaeaa&spx=%2F#vless-gRPC-reality
vless://221ff905-b783-41a0-a6a6-8089eaf3b34b@abc.def.xyz:443?security=reality&type=grpc&headerType=&authority=abc.def.xyz&serviceName=name&mode=gun&sni=abc.def.xyz&fp=chrome&pbk=C3nhDJw02ZU_rjx4GbC54Sp79-ysF5lWIQVWdY4FOnE&sid=#vless-gRPC-reality-mode
vless://af1f8b5f-26c9-4fe8-8ce7-6d6366c5c9ce@127.0.0.1:47904?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com#vless-gRPC-tls vless://af1f8b5f-26c9-4fe8-8ce7-6d6366c5c9ce@127.0.0.1:47904?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com#vless-gRPC-tls
vless://95f2c4bb-abcb-47ba-bfad-e181c03e4659@127.0.0.1:34530?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&allowInsecure=1&sni=google.com#vless-gRPC-tls-insecure vless://95f2c4bb-abcb-47ba-bfad-e181c03e4659@127.0.0.1:34530?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&allowInsecure=1&sni=google.com#vless-gRPC-tls-insecure
vless://bd39490f-9a4f-49b2-96b6-824190cf89e9@127.0.0.1:27779?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com&ech=AF3%2BDQBZAAAgACBc%2FiNdo4QkTt9eQCQgkOiJVSfA9G6UWAyipaBFtBD%2FVQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAApnb29nbGUuY29tAAA%3D#vless-gRPC-tls-ech vless://bd39490f-9a4f-49b2-96b6-824190cf89e9@127.0.0.1:27779?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com&ech=AF3%2BDQBZAAAgACBc%2FiNdo4QkTt9eQCQgkOiJVSfA9G6UWAyipaBFtBD%2FVQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAApnb29nbGUuY29tAAA%3D#vless-gRPC-tls-ech
@@ -81,4 +82,38 @@ trojan://ou8pLSyx9N@127.0.0.1:17737?type=httpupgrade&path=%2Fhttpupgradepath&hos
# XHTTP # XHTTP
trojan://VEetltxLtw@127.0.0.1:59072?type=xhttp&path=%2Fxhttppath&host=google.com&mode=auto&security=none#trojan-xhttp trojan://VEetltxLtw@127.0.0.1:59072?type=xhttp&path=%2Fxhttppath&host=google.com&mode=auto&security=none#trojan-xhttp
```
## Hysteria2
hysteria2://
```
# With password
hysteria2://password@example.com:443/#hysteria2-password
hysteria2://password@example.com:443/?insecure=1#hysteria2-password-insecure
# With SNI
hysteria2://password@example.com:443/?sni=example.com#hysteria2-password-sni
# With obfuscation
hysteria2://password@example.com:443/?obfs=salamander&obfs-password=obfspassword#hysteria2-obfs
# All parameters combined
hysteria2://mypassword@example.com:8443/?sni=example.com&obfs=salamander&obfs-password=obfspass&insecure=1#hysteria2-all-params
```
hy2://
```
# With password
hy2://password@example.com:443/#hysteria2-password
hy2://password@example.com:443/?insecure=1#hysteria2-password-insecure
# With SNI
hy2://password@example.com:443/?sni=example.com#hysteria2-password-sni
# With obfuscation
hy2://password@example.com:443/?obfs=salamander&obfs-password=obfspassword#hysteria2-obfs
# All parameters combined
hy2://mypassword@example.com:8443/?sni=example.com&obfs=salamander&obfs-password=obfspass&insecure=1#hysteria2-all-params
``` ```

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,38 @@
# SOME DESCRIPTIVE TITLE. # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2025 THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2026 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PODKOP package. # This file is distributed under the same license as the PODKOP package.
# divocat <divocatt@gmail.com>, 2025. # divocatt <210179590+divocatt@users.noreply.github.com>, 2026.
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PODKOP\n" "Project-Id-Version: PODKOP\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-26 12:56+0200\n" "POT-Creation-Date: 2026-01-14 18:21+0200\n"
"PO-Revision-Date: 2025-10-26 12:56+0200\n" "PO-Revision-Date: 2026-01-14 18:21+0200\n"
"Last-Translator: divocat <divocatt@gmail.com>\n" "Last-Translator: divocatt <210179590+divocatt@users.noreply.github.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: src/podkop/tabs/dashboard/initController.ts:342 #: src/podkop/tabs/dashboard/initController.ts:345
msgid "✔ Enabled" msgid "✔ Enabled"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:353 #: src/podkop/tabs/dashboard/initController.ts:356
msgid "✔ Running" msgid "✔ Running"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:343 #: src/podkop/tabs/dashboard/initController.ts:346
msgid "✘ Disabled" msgid "✘ Disabled"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:354 #: src/podkop/tabs/dashboard/initController.ts:357
msgid "✘ Stopped" msgid "✘ Stopped"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:304 #: src/podkop/tabs/dashboard/initController.ts:307
msgid "Active Connections" msgid "Active Connections"
msgstr "" msgstr ""
@@ -40,15 +40,19 @@ msgstr ""
msgid "Additional marking rules found" msgid "Additional marking rules found"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:198
msgid "Applicable for SOCKS and Shadowsocks proxy" msgid "Applicable for SOCKS and Shadowsocks proxy"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:356 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:443
msgid "At least one valid domain must be specified. Comments-only content is not allowed." msgid "At least one valid domain must be specified. Comments-only content is not allowed."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:437 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:524
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed." msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
msgstr "" msgstr ""
@@ -72,11 +76,11 @@ msgstr ""
msgid "Browser is using FakeIP correctly" msgid "Browser is using FakeIP correctly"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:329 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:348
msgid "Cache File Path" msgid "Cache File Path"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:343 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:362
msgid "Cache file path cannot be empty" msgid "Cache file path cannot be empty"
msgstr "" msgstr ""
@@ -115,11 +119,11 @@ msgstr ""
msgid "Close" msgid "Close"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:211 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:298
msgid "Community Lists" msgid "Community Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:316 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:335
msgid "Config File Path" msgid "Config File Path"
msgstr "" msgstr ""
@@ -175,16 +179,16 @@ msgstr ""
msgid "Disable autostart" msgid "Disable autostart"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:265
msgid "Disable QUIC" msgid "Disable QUIC"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:266
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming" msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:302 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:389
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:382 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:469
msgid "Disabled" msgid "Disabled"
msgstr "" msgstr ""
@@ -192,17 +196,17 @@ msgstr ""
msgid "DNS on router" msgid "DNS on router"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:179 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
msgid "DNS over HTTPS (DoH)" msgid "DNS over HTTPS (DoH)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:180 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:267
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
msgid "DNS over TLS (DoT)" msgid "DNS over TLS (DoT)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:176 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:263
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
msgid "DNS Protocol Type" msgid "DNS Protocol Type"
msgstr "" msgstr ""
@@ -211,7 +215,7 @@ msgstr ""
msgid "DNS Rewrite TTL" msgid "DNS Rewrite TTL"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:189 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:276
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
msgid "DNS Server" msgid "DNS Server"
msgstr "" msgstr ""
@@ -224,16 +228,16 @@ msgstr ""
msgid "Do not panic, everything can be fixed, just..." msgid "Do not panic, everything can be fixed, just..."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:166 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:253
msgid "Domain Resolver" msgid "Domain Resolver"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:307 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:326
msgid "Dont Touch My DHCP!" msgid "Dont Touch My DHCP!"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:238 #: src/podkop/tabs/dashboard/initController.ts:241
#: src/podkop/tabs/dashboard/initController.ts:272 #: src/podkop/tabs/dashboard/initController.ts:275
msgid "Downlink" msgid "Downlink"
msgstr "" msgstr ""
@@ -241,21 +245,21 @@ msgstr ""
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:269 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:288
msgid "Download Lists via Proxy/VPN" msgid "Download Lists via Proxy/VPN"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:278 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:297
msgid "Download Lists via specific proxy section" msgid "Download Lists via specific proxy section"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:270 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:289
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:279 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:298
msgid "Downloading all lists via specific Proxy/VPN" msgid "Downloading all lists via specific Proxy/VPN"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:303 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:390
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:383 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:470
msgid "Dynamic List" msgid "Dynamic List"
msgstr "" msgstr ""
@@ -263,11 +267,11 @@ msgstr ""
msgid "Enable autostart" msgid "Enable autostart"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:167 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:254
msgid "Enable built-in DNS resolver for domains handled by this section" msgid "Enable built-in DNS resolver for domains handled by this section"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:575 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:662
msgid "Enable Mixed Proxy" msgid "Enable Mixed Proxy"
msgstr "" msgstr ""
@@ -275,7 +279,7 @@ msgstr ""
msgid "Enable Output Network Interface" msgid "Enable Output Network Interface"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:576 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:663
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies" msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
msgstr "" msgstr ""
@@ -283,27 +287,47 @@ msgstr ""
msgid "Enable YACD" msgid "Enable YACD"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
msgid "Enable YACD WAN Access"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
msgid "Enter complete outbound configuration in JSON format" msgid "Enter complete outbound configuration in JSON format"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:338 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:425
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //" msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:312 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:399
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com" msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:392 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:479
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses" msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:365 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:137
msgid "Every 1 minute"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:138
msgid "Every 3 minutes"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:136
msgid "Every 30 seconds"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:139
msgid "Every 5 minutes"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:402
msgid "Exclude NTP" msgid "Exclude NTP"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:403
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN" msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
msgstr "" msgstr ""
@@ -321,11 +345,11 @@ msgid "Failed to execute!"
msgstr "" msgstr ""
#: src/podkop/methods/custom/getDashboardSections.ts:117 #: src/podkop/methods/custom/getDashboardSections.ts:117
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:58 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:59
msgid "Fastest" msgid "Fastest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:550 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:637
msgid "Fully Routed IPs" msgid "Fully Routed IPs"
msgstr "" msgstr ""
@@ -366,6 +390,58 @@ msgstr ""
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y" msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
msgstr "" msgstr ""
#: src/validators/validateHysteriaUrl.ts:76
msgid "Invalid HY2 URL: insecure must be 0 or 1"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:62
msgid "Invalid HY2 URL: invalid port number"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:32
msgid "Invalid HY2 URL: missing credentials/server"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:49
msgid "Invalid HY2 URL: missing host"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:43
msgid "Invalid HY2 URL: missing host & port"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:38
msgid "Invalid HY2 URL: missing password"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:53
msgid "Invalid HY2 URL: missing port"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:19
msgid "Invalid HY2 URL: must not contain spaces"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:12
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:99
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:115
msgid "Invalid HY2 URL: parsing failed"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:108
msgid "Invalid HY2 URL: sni cannot be empty"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:88
msgid "Invalid HY2 URL: unsupported obfs type"
msgstr ""
#: src/validators/validateIp.ts:11 #: src/validators/validateIp.ts:11
msgid "Invalid IP address" msgid "Invalid IP address"
msgstr "" msgstr ""
@@ -466,7 +542,8 @@ msgstr ""
msgid "Invalid Trojan URL: parsing failed" msgid "Invalid Trojan URL: parsing failed"
msgstr "" msgstr ""
#: src/validators/validateUrl.ts:18 #: src/validators/validateUrl.ts:8
#: src/validators/validateUrl.ts:31
msgid "Invalid URL format" msgid "Invalid URL format"
msgstr "" msgstr ""
@@ -486,27 +563,31 @@ msgstr ""
msgid "Latest" msgid "Latest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:276
msgid "List Update Frequency" msgid "List Update Frequency"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:458 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:545
msgid "Local Domain Lists" msgid "Local Domain Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:568
msgid "Local Subnet Lists" msgid "Local Subnet Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:384
msgid "Log Level"
msgstr ""
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:72 #: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:72
msgid "Main DNS" msgid "Main DNS"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:308 #: src/podkop/tabs/dashboard/initController.ts:311
msgid "Memory Usage" msgid "Memory Usage"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:586 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:673
msgid "Mixed Proxy Port" msgid "Mixed Proxy Port"
msgstr "" msgstr ""
@@ -514,7 +595,11 @@ msgstr ""
msgid "Monitored Interfaces" msgid "Monitored Interfaces"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:120 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:163
msgid "Must be a number in the range of 50 - 1000"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:207
msgid "Network Interface" msgid "Network Interface"
msgstr "" msgstr ""
@@ -526,9 +611,9 @@ msgstr ""
msgid "Not implement yet" msgid "Not implement yet"
msgstr "" msgstr ""
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:74 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:75
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:80 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:81
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:99 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:100
msgid "Not responding" msgid "Not responding"
msgstr "" msgstr ""
@@ -544,7 +629,7 @@ msgstr ""
msgid "Operation timed out" msgid "Operation timed out"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:26 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:28
msgid "Outbound Config" msgid "Outbound Config"
msgstr "" msgstr ""
@@ -564,15 +649,15 @@ msgstr ""
msgid "Path cannot be empty" msgid "Path cannot be empty"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:347 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
msgid "Path must be absolute (start with /)" msgid "Path must be absolute (start with /)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:356 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:375
msgid "Path must contain at least one directory (like /tmp/cache.db)" msgid "Path must contain at least one directory (like /tmp/cache.db)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:351 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:370
msgid "Path must end with cache.db" msgid "Path must end with cache.db"
msgstr "" msgstr ""
@@ -584,7 +669,7 @@ msgstr ""
msgid "Pending" msgid "Pending"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:340 #: src/podkop/tabs/dashboard/initController.ts:343
msgid "Podkop" msgid "Podkop"
msgstr "" msgstr ""
@@ -592,11 +677,11 @@ msgstr ""
msgid "Podkop Settings" msgid "Podkop Settings"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:308 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:327
msgid "Podkop will not modify your DHCP configuration" msgid "Podkop will not modify your DHCP configuration"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:34 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:35
msgid "Proxy Configuration URL" msgid "Proxy Configuration URL"
msgstr "" msgstr ""
@@ -608,15 +693,15 @@ msgstr ""
msgid "Proxy traffic is routed via FakeIP" msgid "Proxy traffic is routed via FakeIP"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:332
msgid "Regional options cannot be used together" msgid "Regional options cannot be used together"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:591
msgid "Remote Domain Lists" msgid "Remote Domain Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:527 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:614
msgid "Remote Subnet Lists" msgid "Remote Subnet Lists"
msgstr "" msgstr ""
@@ -632,7 +717,7 @@ msgstr ""
msgid "Router DNS is routed through sing-box" msgid "Router DNS is routed through sing-box"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:376 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:413
msgid "Routing Excluded IPs" msgid "Routing Excluded IPs"
msgstr "" msgstr ""
@@ -664,15 +749,19 @@ msgstr ""
msgid "Run Diagnostic" msgid "Run Diagnostic"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:351
msgid "Russia inside restrictions" msgid "Russia inside restrictions"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
msgid "Sections" msgid "Sections"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:212 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299
msgid "Select a predefined list for routing" msgid "Select a predefined list for routing"
msgstr "" msgstr ""
@@ -684,7 +773,7 @@ msgstr ""
msgid "Select DNS protocol to use" msgid "Select DNS protocol to use"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:258 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:277
msgid "Select how often the domain or subnet lists are updated automatically" msgid "Select how often the domain or subnet lists are updated automatically"
msgstr "" msgstr ""
@@ -692,35 +781,39 @@ msgstr ""
msgid "Select how to configure the proxy" msgid "Select how to configure the proxy"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:121 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:208
msgid "Select network interface for VPN connection" msgid "Select network interface for VPN connection"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:190 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:277
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
msgid "Select or enter DNS server address" msgid "Select or enter DNS server address"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:330 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:349
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing" msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:317 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:336
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing" msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:177 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264
msgid "Select the DNS protocol type for the domain resolver" msgid "Select the DNS protocol type for the domain resolver"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:300 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:387
msgid "Select the list type for adding custom domains" msgid "Select the list type for adding custom domains"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:380 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:467
msgid "Select the list type for adding custom subnets" msgid "Select the list type for adding custom subnets"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:385
msgid "Select the log level for sing-box"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:90 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:90
msgid "Select the network interface from which the traffic will originate" msgid "Select the network interface from which the traffic will originate"
msgstr "" msgstr ""
@@ -733,7 +826,15 @@ msgstr ""
msgid "Select the WAN interfaces to be monitored" msgid "Select the WAN interfaces to be monitored"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:337 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:26
msgid "Selector"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
msgid "Selector Proxy Links"
msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:340
msgid "Services info" msgid "Services info"
msgstr "" msgstr ""
@@ -746,7 +847,7 @@ msgstr ""
msgid "Show sing-box config" msgid "Show sing-box config"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:351 #: src/podkop/tabs/dashboard/initController.ts:354
msgid "Sing-box" msgid "Sing-box"
msgstr "" msgstr ""
@@ -771,31 +872,31 @@ msgid "Sing-box service exist"
msgstr "" msgstr ""
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67 #: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
msgid "Sing-box version >= 1.12.4" msgid "Sing-box version is compatible (newer than 1.12.4)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
msgid "Source Network Interface" msgid "Source Network Interface"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:377 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:414
msgid "Specify a local IP address to be excluded from routing" msgid "Specify a local IP address to be excluded from routing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:551 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:638
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route" msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:505 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:592
msgid "Specify remote URLs to download and use domain lists" msgid "Specify remote URLs to download and use domain lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:528 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:615
msgid "Specify remote URLs to download and use subnet lists" msgid "Specify remote URLs to download and use subnet lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:459 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:546
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:482 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:569
msgid "Specify the path to the list file located on the router filesystem" msgid "Specify the path to the list file located on the router filesystem"
msgstr "" msgstr ""
@@ -811,7 +912,7 @@ msgstr ""
msgid "Successfully copied!" msgid "Successfully copied!"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:301 #: src/podkop/tabs/dashboard/initController.ts:304
msgid "System info" msgid "System info"
msgstr "" msgstr ""
@@ -827,27 +928,36 @@ msgstr ""
msgid "Test latency" msgid "Test latency"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:304 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:471
msgid "Text List" msgid "Text List"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:384
msgid "Text List (comma/space/newline separated)"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
msgid "The DNS server used to look up the IP address of an upstream DNS server" msgid "The DNS server used to look up the IP address of an upstream DNS server"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:134
msgid "The interval between connectivity tests"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:147
msgid "The maximum difference in response times (ms) allowed when comparing servers"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:170
msgid "The URL used to test server connectivity"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
msgid "Time in seconds for DNS record caching (default: 60)" msgid "Time in seconds for DNS record caching (default: 60)"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:235 #: src/podkop/tabs/dashboard/initController.ts:238
msgid "Traffic" msgid "Traffic"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:265 #: src/podkop/tabs/dashboard/initController.ts:268
msgid "Traffic Total" msgid "Traffic Total"
msgstr "" msgstr ""
@@ -863,12 +973,12 @@ msgstr ""
msgid "TTL value cannot be empty" msgid "TTL value cannot be empty"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:181 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:268
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
msgid "UDP (Unprotected DNS)" msgid "UDP (Unprotected DNS)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:197
msgid "UDP over TCP" msgid "UDP over TCP"
msgstr "" msgstr ""
@@ -886,16 +996,16 @@ msgstr ""
msgid "Unknown error" msgid "Unknown error"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:237 #: src/podkop/tabs/dashboard/initController.ts:240
#: src/podkop/tabs/dashboard/initController.ts:268 #: src/podkop/tabs/dashboard/initController.ts:271
msgid "Uplink" msgid "Uplink"
msgstr "" msgstr ""
#: src/validators/validateProxyUrl.ts:29 #: src/validators/validateProxyUrl.ts:37
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://" msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
msgstr "" msgstr ""
#: src/validators/validateUrl.ts:13 #: src/validators/validateUrl.ts:17
msgid "URL must use one of the following protocols:" msgid "URL must use one of the following protocols:"
msgstr "" msgstr ""
@@ -903,31 +1013,43 @@ msgstr ""
msgid "URLTest" msgid "URLTest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:133
msgid "URLTest Check Interval"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
msgid "URLTest Proxy Links" msgid "URLTest Proxy Links"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:169
msgid "URLTest Testing URL"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:146
msgid "URLTest Tolerance"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:386
msgid "User Domain List Type" msgid "User Domain List Type"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:398
msgid "User Domains" msgid "User Domains"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:337 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:424
msgid "User Domains List" msgid "User Domains List"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:379 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:466
msgid "User Subnet List Type" msgid "User Subnet List Type"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:478
msgid "User Subnets" msgid "User Subnets"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:417 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504
msgid "User Subnets List" msgid "User Subnets List"
msgstr "" msgstr ""
@@ -935,6 +1057,7 @@ msgstr ""
#: src/validators/validateDns.ts:18 #: src/validators/validateDns.ts:18
#: src/validators/validateDomain.ts:13 #: src/validators/validateDomain.ts:13
#: src/validators/validateDomain.ts:30 #: src/validators/validateDomain.ts:30
#: src/validators/validateHysteriaUrl.ts:113
#: src/validators/validateIp.ts:8 #: src/validators/validateIp.ts:8
#: src/validators/validateOutboundJson.ts:7 #: src/validators/validateOutboundJson.ts:7
#: src/validators/validatePath.ts:16 #: src/validators/validatePath.ts:16
@@ -942,13 +1065,13 @@ msgstr ""
#: src/validators/validateSocksUrl.ts:80 #: src/validators/validateSocksUrl.ts:80
#: src/validators/validateSubnet.ts:38 #: src/validators/validateSubnet.ts:38
#: src/validators/validateTrojanUrl.ts:59 #: src/validators/validateTrojanUrl.ts:59
#: src/validators/validateUrl.ts:16 #: src/validators/validateUrl.ts:28
#: src/validators/validateVlessUrl.ts:108 #: src/validators/validateVlessUrl.ts:108
msgid "Valid" msgid "Valid"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:370 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:457
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:449 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:536
msgid "Validation errors:" msgid "Validation errors:"
msgstr "" msgstr ""
@@ -961,14 +1084,24 @@ msgstr ""
msgid "Visit Wiki" msgid "Visit Wiki"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:247 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:36
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:88
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
msgid "vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:334
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed." msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:353
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection." msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:256
msgid "YACD Secret Key"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
msgid "You can select Output Network Interface, by default autodetect" msgid "You can select Output Network Interface, by default autodetect"
msgstr "" msgstr ""

View File

@@ -1,15 +1,15 @@
# RU translations for PODKOP package. # RU translations for PODKOP package.
# Copyright (C) 2025 THE PODKOP'S COPYRIGHT HOLDER # Copyright (C) 2026 THE PODKOP'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PODKOP package. # This file is distributed under the same license as the PODKOP package.
# divocat, 2025. # divocatt, 2026.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PODKOP\n" "Project-Id-Version: PODKOP\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-26 14:56+0200\n" "POT-Creation-Date: 2026-01-14 20:21+0200\n"
"PO-Revision-Date: 2025-10-26 14:56+0200\n" "PO-Revision-Date: 2026-01-14 20:21+0200\n"
"Last-Translator: divocat\n" "Last-Translator: divocatt\n"
"Language-Team: none\n" "Language-Team: none\n"
"Language: ru\n" "Language: ru\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -35,6 +35,9 @@ msgstr "Активные соединения"
msgid "Additional marking rules found" msgid "Additional marking rules found"
msgstr "Найдены дополнительные правила маркировки" msgstr "Найдены дополнительные правила маркировки"
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
msgid "Applicable for SOCKS and Shadowsocks proxy" msgid "Applicable for SOCKS and Shadowsocks proxy"
msgstr "Применимо для SOCKS и Shadowsocks прокси" msgstr "Применимо для SOCKS и Shadowsocks прокси"
@@ -206,6 +209,9 @@ msgstr "Включить смешанный прокси-сервер, разр
msgid "Enable YACD" msgid "Enable YACD"
msgstr "Включить YACD" msgstr "Включить YACD"
msgid "Enable YACD WAN Access"
msgstr "Включить доступ YACD WAN"
msgid "Enter complete outbound configuration in JSON format" msgid "Enter complete outbound configuration in JSON format"
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON" msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
@@ -218,6 +224,18 @@ msgstr "Введите доменные имена без протоколов,
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses" msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса" msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
msgid "Every 1 minute"
msgstr "Каждую минуту"
msgid "Every 3 minutes"
msgstr "Каждые 3 минуты"
msgid "Every 30 seconds"
msgstr "Каждые 30 секунд"
msgid "Every 5 minutes"
msgstr "Каждые 5 минут"
msgid "Exclude NTP" msgid "Exclude NTP"
msgstr "Исключить NTP" msgstr "Исключить NTP"
@@ -263,6 +281,45 @@ msgstr "Неверный домен"
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y" msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y" msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
msgid "Invalid HY2 URL: insecure must be 0 or 1"
msgstr "Неверный URL Hysteria2: параметр insecure должен быть 0 или 1"
msgid "Invalid HY2 URL: invalid port number"
msgstr "Неверный URL Hysteria2: неверный номер порта"
msgid "Invalid HY2 URL: missing credentials/server"
msgstr "Неверный URL Hysteria2: отсутствуют учетные данные/сервер"
msgid "Invalid HY2 URL: missing host"
msgstr "Неверный URL Hysteria2: отсутствует хост"
msgid "Invalid HY2 URL: missing host & port"
msgstr "Неверный URL Hysteria2: отсутствуют хост и порт"
msgid "Invalid HY2 URL: missing password"
msgstr "Неверный URL Hysteria2: отсутствует пароль"
msgid "Invalid HY2 URL: missing port"
msgstr "Неверный URL Hysteria2: отсутствует порт"
msgid "Invalid HY2 URL: must not contain spaces"
msgstr "Неверный URL Hysteria2: не должен содержать пробелов"
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
msgstr "Неверный URL Hysteria2: должен начинаться с hysteria2:// или hy2://"
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
msgstr "Неверный URL Hysteria2: требуется obfs-password, когда установлен obfs"
msgid "Invalid HY2 URL: parsing failed"
msgstr "Неверный URL Hysteria2: ошибка разбора"
msgid "Invalid HY2 URL: sni cannot be empty"
msgstr "Неверный URL Hysteria2: sni не может быть пустым"
msgid "Invalid HY2 URL: unsupported obfs type"
msgstr "Неверный URL Hysteria2: неподдерживаемый тип obfs"
msgid "Invalid IP address" msgid "Invalid IP address"
msgstr "Неверный IP-адрес" msgstr "Неверный IP-адрес"
@@ -362,6 +419,9 @@ msgstr "Локальные списки доменов"
msgid "Local Subnet Lists" msgid "Local Subnet Lists"
msgstr "Локальные списки подсетей" msgstr "Локальные списки подсетей"
msgid "Log Level"
msgstr "Уровень логов"
msgid "Main DNS" msgid "Main DNS"
msgstr "Основной DNS" msgstr "Основной DNS"
@@ -374,6 +434,9 @@ msgstr "Порт смешанного прокси"
msgid "Monitored Interfaces" msgid "Monitored Interfaces"
msgstr "Наблюдаемые интерфейсы" msgstr "Наблюдаемые интерфейсы"
msgid "Must be a number in the range of 50 - 1000"
msgstr "Должно быть числом от 50 до 1000"
msgid "Network Interface" msgid "Network Interface"
msgstr "Сетевой интерфейс" msgstr "Сетевой интерфейс"
@@ -482,6 +545,9 @@ msgstr "Запустить диагностику"
msgid "Russia inside restrictions" msgid "Russia inside restrictions"
msgstr "Ограничения Russia inside" msgstr "Ограничения Russia inside"
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
msgstr "Секретный ключ для аутентификации удаленного доступа к YACD при включенном доступе через WAN."
msgid "Sections" msgid "Sections"
msgstr "Секции" msgstr "Секции"
@@ -521,6 +587,9 @@ msgstr "Выберите тип списка для добавления пол
msgid "Select the list type for adding custom subnets" msgid "Select the list type for adding custom subnets"
msgstr "Выберите тип списка для добавления пользовательских подсетей" msgstr "Выберите тип списка для добавления пользовательских подсетей"
msgid "Select the log level for sing-box"
msgstr "Выберите уровень логов для sing-box"
msgid "Select the network interface from which the traffic will originate" msgid "Select the network interface from which the traffic will originate"
msgstr "Выберите сетевой интерфейс, с которого будет исходить трафик" msgstr "Выберите сетевой интерфейс, с которого будет исходить трафик"
@@ -530,6 +599,12 @@ msgstr "Выберите сетевой интерфейс, на который
msgid "Select the WAN interfaces to be monitored" msgid "Select the WAN interfaces to be monitored"
msgstr "Выберите WAN интерфейсы для мониторинга" msgstr "Выберите WAN интерфейсы для мониторинга"
msgid "Selector"
msgstr "Selector"
msgid "Selector Proxy Links"
msgstr "Ссылки прокси для Selector"
msgid "Services info" msgid "Services info"
msgstr "Информация о сервисах" msgstr "Информация о сервисах"
@@ -557,8 +632,8 @@ msgstr "Процесс sing-box запущен"
msgid "Sing-box service exist" msgid "Sing-box service exist"
msgstr "Сервис sing-box существует" msgstr "Сервис sing-box существует"
msgid "Sing-box version >= 1.12.4" msgid "Sing-box version is compatible (newer than 1.12.4)"
msgstr "Версия sing-box >= 1.12.4" msgstr "Версия Sing-box совместима (новее 1.12.4)"
msgid "Source Network Interface" msgid "Source Network Interface"
msgstr "Сетевой интерфейс источника" msgstr "Сетевой интерфейс источника"
@@ -602,12 +677,18 @@ msgstr "Тестирование задержки"
msgid "Text List" msgid "Text List"
msgstr "Текстовый список" msgstr "Текстовый список"
msgid "Text List (comma/space/newline separated)"
msgstr "Текстовый список (через запятую, пробел или новую строку)"
msgid "The DNS server used to look up the IP address of an upstream DNS server" msgid "The DNS server used to look up the IP address of an upstream DNS server"
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера" msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
msgid "The interval between connectivity tests"
msgstr "Интервал между тестами подключения"
msgid "The maximum difference in response times (ms) allowed when comparing servers"
msgstr "Максимально допустимая разница во времени отклика (мс) при сравнении серверов"
msgid "The URL used to test server connectivity"
msgstr "URL-адрес, используемый для проверки подключения к серверу"
msgid "Time in seconds for DNS record caching (default: 60)" msgid "Time in seconds for DNS record caching (default: 60)"
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)" msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
@@ -641,8 +722,8 @@ msgstr "Неизвестная ошибка"
msgid "Uplink" msgid "Uplink"
msgstr "Исходящий" msgstr "Исходящий"
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://" msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
msgstr "URL должен начинаться с vless://, ss://, trojan:// или socks4/5://" msgstr "URL должен начинаться с vless://, ss://, trojan://, socks4/5:// или hysteria2:// hy2://"
msgid "URL must use one of the following protocols:" msgid "URL must use one of the following protocols:"
msgstr "URL должен использовать один из следующих протоколов:" msgstr "URL должен использовать один из следующих протоколов:"
@@ -650,9 +731,18 @@ msgstr "URL должен использовать один из следующи
msgid "URLTest" msgid "URLTest"
msgstr "URLTest" msgstr "URLTest"
msgid "URLTest Check Interval"
msgstr "Интервал проверки URLTest"
msgid "URLTest Proxy Links" msgid "URLTest Proxy Links"
msgstr "Ссылки прокси для URLTest" msgstr "Ссылки прокси для URLTest"
msgid "URLTest Testing URL"
msgstr "URLTest ссылка для проверки"
msgid "URLTest Tolerance"
msgstr "URLTest допустимое отклонение"
msgid "User Domain List Type" msgid "User Domain List Type"
msgstr "Тип пользовательского списка доменов" msgstr "Тип пользовательского списка доменов"
@@ -683,11 +773,17 @@ msgstr "Посмотреть логи"
msgid "Visit Wiki" msgid "Visit Wiki"
msgstr "Перейти в wiki" msgstr "Перейти в wiki"
msgid "vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links"
msgstr ""
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed." msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
msgstr "Предупреждение: %s нельзя использовать вместе с %s. Предыдущие варианты были удалены." msgstr "Предупреждение: %s нельзя использовать вместе с %s. Предыдущие варианты были удалены."
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection." msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных." msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
msgid "YACD Secret Key"
msgstr "Секретный ключ YACD"
msgid "You can select Output Network Interface, by default autodetect" msgid "You can select Output Network Interface, by default autodetect"
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически." msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."

View File

@@ -13,11 +13,11 @@
"test": "vitest", "test": "vitest",
"ci": "yarn format && yarn lint --max-warnings=0 && yarn test --run && yarn build", "ci": "yarn format && yarn lint --max-warnings=0 && yarn test --run && yarn build",
"watch:sftp": "node watch-upload.js", "watch:sftp": "node watch-upload.js",
"locales:exctract-calls": "node extract-calls.js", "locales:extract-calls": "node extract-calls.js",
"locales:generate-pot": "node generate-pot.js", "locales:generate-pot": "node generate-pot.js",
"locales:generate-po:ru": "node generate-po.js ru", "locales:generate-po:ru": "node generate-po.js ru",
"locales:distribute": "node distribute-locales.js", "locales:distribute": "node distribute-locales.js",
"locales:actualize": "yarn locales:exctract-calls && yarn locales:generate-pot && yarn locales:generate-po:ru && yarn locales:distribute" "locales:actualize": "yarn locales:extract-calls && yarn locales:generate-pot && yarn locales:generate-po:ru && yarn locales:distribute"
}, },
"devDependencies": { "devDependencies": {
"@babel/parser": "7.28.4", "@babel/parser": "7.28.4",

View File

@@ -26,6 +26,7 @@ export const ALLOWED_WITH_RUSSIA_INSIDE = [
'hetzner', 'hetzner',
'ovh', 'ovh',
'hodca', 'hodca',
'roblox',
'digitalocean', 'digitalocean',
'cloudfront', 'cloudfront',
]; ];
@@ -50,6 +51,7 @@ export const DOMAIN_LIST_OPTIONS = {
google_ai: 'Google AI', google_ai: 'Google AI',
google_play: 'Google Play', google_play: 'Google Play',
hodca: 'H.O.D.C.A', hodca: 'H.O.D.C.A',
roblox: 'Roblox',
hetzner: 'Hetzner ASN', hetzner: 'Hetzner ASN',
ovh: 'OVH ASN', ovh: 'OVH ASN',
digitalocean: 'Digital Ocean ASN', digitalocean: 'Digital Ocean ASN',

View File

@@ -0,0 +1,9 @@
import { getConfigSections } from './getConfigSections';
export async function getClashApiSecret() {
const sections = await getConfigSections();
const settings = sections.find((section) => section['.type'] === 'settings');
return settings?.yacd_secret_key || '';
}

View File

@@ -86,6 +86,37 @@ export async function getDashboardSections(): Promise<IGetDashboardSectionsRespo
}; };
} }
if (section.proxy_config_type === 'selector') {
const selector = proxies.find(
(proxy) => proxy.code === `${section['.name']}-out`,
);
const links = section.selector_proxy_links ?? [];
const outbounds = links
.map((link, index) => ({
link,
outbound: proxies.find(
(item) => item.code === `${section['.name']}-${index + 1}-out`,
),
}))
.map((item) => ({
code: item?.outbound?.code || '',
displayName:
getProxyUrlName(item.link) || item?.outbound?.value?.name || '',
latency: item?.outbound?.value?.history?.[0]?.delay || 0,
type: item?.outbound?.value?.type || '',
selected: selector?.value?.now === item?.outbound?.code,
}));
return {
withTagSelect: true,
code: selector?.code || section['.name'],
displayName: section['.name'],
outbounds,
};
}
if (section.proxy_config_type === 'urltest') { if (section.proxy_config_type === 'urltest') {
const selector = proxies.find( const selector = proxies.find(
(proxy) => proxy.code === `${section['.name']}-out`, (proxy) => proxy.code === `${section['.name']}-out`,

View File

@@ -1,7 +1,9 @@
import { getConfigSections } from './getConfigSections'; import { getConfigSections } from './getConfigSections';
import { getDashboardSections } from './getDashboardSections'; import { getDashboardSections } from './getDashboardSections';
import { getClashApiSecret } from './getClashApiSecret';
export const CustomPodkopMethods = { export const CustomPodkopMethods = {
getConfigSections, getConfigSections,
getDashboardSections, getDashboardSections,
getClashApiSecret,
}; };

View File

@@ -31,12 +31,12 @@ export const PodkopShellMethods = {
getClashApiProxyLatency: async (tag: string) => getClashApiProxyLatency: async (tag: string) =>
callBaseMethod<Podkop.GetClashApiProxyLatency>( callBaseMethod<Podkop.GetClashApiProxyLatency>(
Podkop.AvailableMethods.CLASH_API, Podkop.AvailableMethods.CLASH_API,
[Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag], [Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag, '5000'],
), ),
getClashApiGroupLatency: async (tag: string) => getClashApiGroupLatency: async (tag: string) =>
callBaseMethod<Podkop.GetClashApiGroupLatency>( callBaseMethod<Podkop.GetClashApiGroupLatency>(
Podkop.AvailableMethods.CLASH_API, Podkop.AvailableMethods.CLASH_API,
[Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag], [Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag, '10000'],
), ),
setClashApiGroupProxy: async (group: string, proxy: string) => setClashApiGroupProxy: async (group: string, proxy: string) =>
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [ callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [

View File

@@ -8,6 +8,7 @@ import { CustomPodkopMethods, PodkopShellMethods } from '../../methods';
import { logger, socket, store, StoreType } from '../../services'; import { logger, socket, store, StoreType } from '../../services';
import { renderSections, renderWidget } from './partials'; import { renderSections, renderWidget } from './partials';
import { fetchServicesInfo } from '../../fetchers'; import { fetchServicesInfo } from '../../fetchers';
import { getClashApiSecret } from '../../methods/custom/getClashApiSecret';
// Fetchers // Fetchers
@@ -38,8 +39,10 @@ async function fetchDashboardSections() {
} }
async function connectToClashSockets() { async function connectToClashSockets() {
const clashApiSecret = await getClashApiSecret();
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/traffic?token=`, `${getClashWsUrl()}/traffic?token=${clashApiSecret}`,
(msg) => { (msg) => {
const parsedMsg = JSON.parse(msg); const parsedMsg = JSON.parse(msg);
@@ -68,7 +71,7 @@ async function connectToClashSockets() {
); );
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/connections?token=`, `${getClashWsUrl()}/connections?token=${clashApiSecret}`,
(msg) => { (msg) => {
const parsedMsg = JSON.parse(msg); const parsedMsg = JSON.parse(msg);

View File

@@ -43,6 +43,7 @@ export async function runSectionsCheck() {
const selectedOutbound = section.outbounds.find( const selectedOutbound = section.outbounds.find(
(item) => item.selected, (item) => item.selected,
); );
const isUrlTest = selectedOutbound?.type === 'URLTest'; const isUrlTest = selectedOutbound?.type === 'URLTest';
const success = latencyGroup.success && !latencyGroup.data.message; const success = latencyGroup.success && !latencyGroup.data.message;
@@ -65,13 +66,13 @@ export async function runSectionsCheck() {
if (selectedProxyDelay) { if (selectedProxyDelay) {
return { return {
success: true, success: true,
latency: `[${selectedOutbound?.code ?? ''}] ${selectedProxyDelay}ms`, latency: `[${selectedOutbound?.displayName ?? ''}] ${selectedProxyDelay}ms`,
}; };
} }
return { return {
success: false, success: false,
latency: `[${selectedOutbound?.code ?? ''}] ${_('Not responding')}`, latency: `[${selectedOutbound?.displayName ?? ''}] ${_('Not responding')}`,
}; };
} }

View File

@@ -64,7 +64,7 @@ export async function runSingBoxCheck() {
}, },
{ {
state: data.sing_box_version_ok ? 'success' : 'error', state: data.sing_box_version_ok ? 'success' : 'error',
key: _('Sing-box version >= 1.12.4'), key: _('Sing-box version is compatible (newer than 1.12.4)'),
value: '', value: '',
}, },
{ {

View File

@@ -288,7 +288,10 @@ async function handleShowSingBoxConfig() {
if (showSingBoxConfig.success) { if (showSingBoxConfig.success) {
ui.showModal( ui.showModal(
_('Show sing-box config'), _('Show sing-box config'),
renderModal(showSingBoxConfig.data as string, 'show_sing_box_config'), renderModal(
JSON.stringify(showSingBoxConfig.data, null, 2),
'show_sing_box_config',
),
); );
} else { } else {
logger.error( logger.error(

View File

@@ -95,6 +95,12 @@ export namespace Podkop {
urltest_proxy_links: string[]; urltest_proxy_links: string[];
} }
export interface ConfigProxySelectorSection {
connection_type: 'proxy';
proxy_config_type: 'selector';
selector_proxy_links: string[];
}
export interface ConfigProxyUrlSection { export interface ConfigProxyUrlSection {
connection_type: 'proxy'; connection_type: 'proxy';
proxy_config_type: 'url'; proxy_config_type: 'url';
@@ -118,6 +124,7 @@ export namespace Podkop {
export type ConfigBaseSection = export type ConfigBaseSection =
| ConfigProxyUrlTestSection | ConfigProxyUrlTestSection
| ConfigProxySelectorSection
| ConfigProxyUrlSection | ConfigProxyUrlSection
| ConfigProxyOutboundSection | ConfigProxyOutboundSection
| ConfigVpnSection | ConfigVpnSection
@@ -126,6 +133,7 @@ export namespace Podkop {
export type ConfigSection = ConfigBaseSection & { export type ConfigSection = ConfigBaseSection & {
'.name': string; '.name': string;
'.type': 'settings' | 'section'; '.type': 'settings' | 'section';
yacd_secret_key?: string;
}; };
export interface MethodSuccessResponse<T> { export interface MethodSuccessResponse<T> {

View File

@@ -0,0 +1,74 @@
import { describe, it, expect } from 'vitest';
import { validateHysteria2Url } from '../validateHysteriaUrl.js';
const validUrls = [
// Basic password-only
['password basic', 'hysteria2://pass@example.com:443/#hy2-basic'],
// insecure=1
[
'insecure allowed',
'hysteria2://pass@example.com:443/?insecure=1#hy2-insecure',
],
// SNI
['SNI param', 'hysteria2://pass@example.com:443/?sni=google.com#hy2-sni'],
// Obfuscation
[
'Obfs + password',
'hysteria2://mypassword@1.1.1.1:8443/?obfs=salamander&obfs-password=abc123#hy2-obfs',
],
// All params
[
'All options combined',
'hysteria2://pw@8.8.8.8:8443/?sni=example.com&obfs=salamander&obfs-password=hello&insecure=1#hy2-full',
],
// Explicit obfs=none (valid)
['obfs none = ok', 'hysteria2://pw@example.com:443/?obfs=none#hy2-none'],
];
const invalidUrls = [
['No prefix', 'pw@example.com:443'],
['Missing password', 'hysteria2://@example.com:443/'],
['Missing host', 'hysteria2://pw@:443/'],
['Missing port', 'hysteria2://pw@example.com/'],
['Non-numeric port', 'hysteria2://pw@example.com:port/'],
['Port out of range', 'hysteria2://pw@example.com:99999/'],
// Obfuscation errors
['Unknown obfs type', 'hysteria2://pw@example.com:443/?obfs=weird'],
[
'obfs without obfs-password',
'hysteria2://pw@example.com:443/?obfs=salamander',
],
// insecure only accepts 0/1
['invalid insecure', 'hysteria2://pw@example.com:443/?insecure=5'],
// SNI empty
['empty sni', 'hysteria2://pw@example.com:443/?sni='],
];
describe('validateHysteria2Url', () => {
describe.each(validUrls)('Valid HY2 URL: %s', (_desc, url) => {
it(`returns valid=true for "${url}"`, () => {
const res = validateHysteria2Url(url);
expect(res.valid).toBe(true);
});
});
describe.each(invalidUrls)('Invalid HY2 URL: %s', (_desc, url) => {
it(`returns valid=false for "${url}"`, () => {
const res = validateHysteria2Url(url);
expect(res.valid).toBe(false);
});
});
it('detects invalid port range', () => {
const res = validateHysteria2Url('hysteria2://pw@example.com:70000/');
expect(res.valid).toBe(false);
});
});

View File

@@ -16,6 +16,7 @@ const invalidUrls = [
['Unsupported protocol (ftp)', 'ftp://example.com'], ['Unsupported protocol (ftp)', 'ftp://example.com'],
['Unsupported protocol (ws)', 'ws://example.com'], ['Unsupported protocol (ws)', 'ws://example.com'],
['Empty string', ''], ['Empty string', ''],
['Without tld', 'https://google'],
]; ];
describe('validateUrl', () => { describe('validateUrl', () => {

View File

@@ -0,0 +1,117 @@
import { ValidationResult } from './types';
import { parseQueryString } from '../helpers/parseQueryString';
export function validateHysteria2Url(url: string): ValidationResult {
try {
const isHY2 = url.startsWith('hysteria2://');
const isHY2Short = url.startsWith('hy2://');
if (!isHY2 && !isHY2Short) {
return {
valid: false,
message: _('Invalid HY2 URL: must start with hysteria2:// or hy2://'),
};
}
if (/\s/.test(url)) {
return {
valid: false,
message: _('Invalid HY2 URL: must not contain spaces'),
};
}
const prefix = isHY2 ? 'hysteria2://' : 'hy2://';
const body = url.slice(prefix.length);
const [mainPart] = body.split('#');
const [authHostPort, queryString] = mainPart.split('?');
if (!authHostPort)
return {
valid: false,
message: _('Invalid HY2 URL: missing credentials/server'),
};
const [passwordPart, hostPortPart] = authHostPort.split('@');
if (!passwordPart)
return { valid: false, message: _('Invalid HY2 URL: missing password') };
if (!hostPortPart)
return {
valid: false,
message: _('Invalid HY2 URL: missing host & port'),
};
const [host, port] = hostPortPart.split(':');
if (!host) {
return { valid: false, message: _('Invalid HY2 URL: missing host') };
}
if (!port) {
return { valid: false, message: _('Invalid HY2 URL: missing port') };
}
const cleanedPort = port.replace('/', '');
const portNum = Number(cleanedPort);
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
return {
valid: false,
message: _('Invalid HY2 URL: invalid port number'),
};
}
if (queryString) {
const params = parseQueryString(queryString);
const paramsKeys = Object.keys(params);
if (
paramsKeys.includes('insecure') &&
!['0', '1'].includes(params.insecure)
) {
return {
valid: false,
message: _('Invalid HY2 URL: insecure must be 0 or 1'),
};
}
const validObfsTypes = ['none', 'salamander'];
if (
paramsKeys.includes('obfs') &&
!validObfsTypes.includes(params.obfs)
) {
return {
valid: false,
message: _('Invalid HY2 URL: unsupported obfs type'),
};
}
if (
paramsKeys.includes('obfs') &&
params.obfs !== 'none' &&
!params['obfs-password']
) {
return {
valid: false,
message: _(
'Invalid HY2 URL: obfs-password required when obfs is set',
),
};
}
if (paramsKeys.includes('sni') && !params.sni) {
return {
valid: false,
message: _('Invalid HY2 URL: sni cannot be empty'),
};
}
}
return { valid: true, message: _('Valid') };
} catch (_e) {
return { valid: false, message: _('Invalid HY2 URL: parsing failed') };
}
}

View File

@@ -3,6 +3,7 @@ import { validateShadowsocksUrl } from './validateShadowsocksUrl';
import { validateVlessUrl } from './validateVlessUrl'; import { validateVlessUrl } from './validateVlessUrl';
import { validateTrojanUrl } from './validateTrojanUrl'; import { validateTrojanUrl } from './validateTrojanUrl';
import { validateSocksUrl } from './validateSocksUrl'; import { validateSocksUrl } from './validateSocksUrl';
import { validateHysteria2Url } from './validateHysteriaUrl';
// TODO refactor current validation and add tests // TODO refactor current validation and add tests
export function validateProxyUrl(url: string): ValidationResult { export function validateProxyUrl(url: string): ValidationResult {
@@ -24,10 +25,17 @@ export function validateProxyUrl(url: string): ValidationResult {
return validateSocksUrl(trimmedUrl); return validateSocksUrl(trimmedUrl);
} }
if (
trimmedUrl.startsWith('hysteria2://') ||
trimmedUrl.startsWith('hy2://')
) {
return validateHysteria2Url(trimmedUrl);
}
return { return {
valid: false, valid: false,
message: _( message: _(
'URL must start with vless://, ss://, trojan://, or socks4/5://', 'URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://',
), ),
}; };
} }

View File

@@ -2,19 +2,31 @@ import { ValidationResult } from './types';
export function validateUrl( export function validateUrl(
url: string, url: string,
protocols: string[] = ['http:', 'https:'], protocols = ['http:', 'https:'],
): ValidationResult { ): ValidationResult {
try { if (!url.length) {
const parsedUrl = new URL(url);
if (!protocols.includes(parsedUrl.protocol)) {
return {
valid: false,
message: `${_('URL must use one of the following protocols:')} ${protocols.join(', ')}`,
};
}
return { valid: true, message: _('Valid') };
} catch (_e) {
return { valid: false, message: _('Invalid URL format') }; return { valid: false, message: _('Invalid URL format') };
} }
const hasValidProtocol = protocols.some((p) => url.indexOf(p + '//') === 0);
if (!hasValidProtocol)
return {
valid: false,
message:
_('URL must use one of the following protocols:') +
' ' +
protocols.join(', '),
};
const regex = new RegExp(
`^(?:${protocols.map((p) => p.replace(':', '')).join('|')})://` +
`(?:[A-Za-z0-9-]+\\.)+[A-Za-z]{2,}(?::\\d+)?(?:/[^\\s]*)?$`,
);
if (regex.test(url)) {
return { valid: true, message: _('Valid') };
}
return { valid: false, message: _('Invalid URL format') };
} }

View File

@@ -109,16 +109,16 @@ main() {
pkg_list_update || { echo "Packages list update failed"; exit 1; } pkg_list_update || { echo "Packages list update failed"; exit 1; }
if [ -f "/etc/init.d/podkop" ]; then if [ -f "/etc/init.d/podkop" ]; then
msg "Podkop is already installed. Upgraded..." msg "Podkop is already installed. Upgrading..."
else else
msg "Installed podkop..." msg "Installing podkop..."
fi fi
if command -v curl >/dev/null 2>&1; then if command -v curl >/dev/null 2>&1; then
check_response=$(curl -s "https://api.github.com/repos/itdoginfo/podkop/releases/latest") check_response=$(curl -s "https://api.github.com/repos/itdoginfo/podkop/releases/latest")
if echo "$check_response" | grep -q 'API rate limit '; then if echo "$check_response" | grep -q 'API rate limit '; then
msg "You've reached rate limit from GitHub. Repeat in five minutes." msg "You've reached the GitHub rate limit. Repeat in five minutes."
exit 1 exit 1
fi fi
fi fi
@@ -143,7 +143,7 @@ main() {
break break
fi fi
fi fi
msg "Download error $filename. Retry..." msg "Download error for $filename. Retrying..."
rm -f "$filepath" rm -f "$filepath"
attempt=$((attempt+1)) attempt=$((attempt+1))
done done
@@ -168,7 +168,7 @@ main() {
fi fi
done done
if [ -n "$file" ]; then if [ -n "$file" ]; then
msg "Installing $file" msg "Installing $file..."
pkg_install "$DOWNLOAD_DIR/$file" pkg_install "$DOWNLOAD_DIR/$file"
sleep 3 sleep 3
fi fi
@@ -183,11 +183,11 @@ main() {
done done
if [ -n "$ru" ]; then if [ -n "$ru" ]; then
if pkg_is_installed luci-i18n-podkop-ru; then if pkg_is_installed luci-i18n-podkop-ru; then
msg "Upgraded ru translation..." msg "Upgrading Russian translation..."
pkg_remove luci-i18n-podkop* pkg_remove luci-i18n-podkop*
pkg_install "$DOWNLOAD_DIR/$ru" pkg_install "$DOWNLOAD_DIR/$ru"
else else
msg "Русский язык интерфейса ставим? y/n (Need a Russian translation?)" msg "Русский язык интерфейса ставим? y/n (Install the Russian interface language?)"
while true; do while true; do
read -r -p '' RUS read -r -p '' RUS
case $RUS in case $RUS in
@@ -236,7 +236,7 @@ check_system() {
fi fi
if ! nslookup google.com >/dev/null 2>&1; then if ! nslookup google.com >/dev/null 2>&1; then
msg "DNS not working" msg "DNS is not working."
exit 1 exit 1
fi fi
@@ -270,7 +270,7 @@ check_system() {
fi fi
if pkg_is_installed https-dns-proxy; then if pkg_is_installed https-dns-proxy; then
msg "Сonflicting package detected: https-dns-proxy. Remove?" msg "Conflicting package detected: https-dns-proxy. Remove?"
while true; do while true; do
read -r -p '' DNSPROXY read -r -p '' DNSPROXY
@@ -300,7 +300,7 @@ sing_box() {
required_version="1.12.4" required_version="1.12.4"
if [ "$(printf '%s\n%s\n' "$sing_box_version" "$required_version" | sort -V | head -n 1)" != "$required_version" ]; then if [ "$(printf '%s\n%s\n' "$sing_box_version" "$required_version" | sort -V | head -n 1)" != "$required_version" ]; then
msg "sing-box version $sing_box_version is older than required $required_version" msg "sing-box version $sing_box_version is older than the required version $required_version."
msg "Removing old version..." msg "Removing old version..."
service podkop stop service podkop stop
pkg_remove sing-box pkg_remove sing-box

View File

@@ -58,18 +58,22 @@ function validateDNS(value) {
// src/validators/validateUrl.ts // src/validators/validateUrl.ts
function validateUrl(url, protocols = ["http:", "https:"]) { function validateUrl(url, protocols = ["http:", "https:"]) {
try { if (!url.length) {
const parsedUrl = new URL(url);
if (!protocols.includes(parsedUrl.protocol)) {
return {
valid: false,
message: `${_("URL must use one of the following protocols:")} ${protocols.join(", ")}`
};
}
return { valid: true, message: _("Valid") };
} catch (_e) {
return { valid: false, message: _("Invalid URL format") }; return { valid: false, message: _("Invalid URL format") };
} }
const hasValidProtocol = protocols.some((p) => url.indexOf(p + "//") === 0);
if (!hasValidProtocol)
return {
valid: false,
message: _("URL must use one of the following protocols:") + " " + protocols.join(", ")
};
const regex = new RegExp(
`^(?:${protocols.map((p) => p.replace(":", "")).join("|")})://(?:[A-Za-z0-9-]+\\.)+[A-Za-z]{2,}(?::\\d+)?(?:/[^\\s]*)?$`
);
if (regex.test(url)) {
return { valid: true, message: _("Valid") };
}
return { valid: false, message: _("Invalid URL format") };
} }
// src/validators/validatePath.ts // src/validators/validatePath.ts
@@ -444,6 +448,92 @@ function validateSocksUrl(url) {
return { valid: true, message: _("Valid") }; return { valid: true, message: _("Valid") };
} }
// src/validators/validateHysteriaUrl.ts
function validateHysteria2Url(url) {
try {
const isHY2 = url.startsWith("hysteria2://");
const isHY2Short = url.startsWith("hy2://");
if (!isHY2 && !isHY2Short) {
return {
valid: false,
message: _("Invalid HY2 URL: must start with hysteria2:// or hy2://")
};
}
if (/\s/.test(url)) {
return {
valid: false,
message: _("Invalid HY2 URL: must not contain spaces")
};
}
const prefix = isHY2 ? "hysteria2://" : "hy2://";
const body = url.slice(prefix.length);
const [mainPart] = body.split("#");
const [authHostPort, queryString] = mainPart.split("?");
if (!authHostPort)
return {
valid: false,
message: _("Invalid HY2 URL: missing credentials/server")
};
const [passwordPart, hostPortPart] = authHostPort.split("@");
if (!passwordPart)
return { valid: false, message: _("Invalid HY2 URL: missing password") };
if (!hostPortPart)
return {
valid: false,
message: _("Invalid HY2 URL: missing host & port")
};
const [host, port] = hostPortPart.split(":");
if (!host) {
return { valid: false, message: _("Invalid HY2 URL: missing host") };
}
if (!port) {
return { valid: false, message: _("Invalid HY2 URL: missing port") };
}
const cleanedPort = port.replace("/", "");
const portNum = Number(cleanedPort);
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
return {
valid: false,
message: _("Invalid HY2 URL: invalid port number")
};
}
if (queryString) {
const params = parseQueryString(queryString);
const paramsKeys = Object.keys(params);
if (paramsKeys.includes("insecure") && !["0", "1"].includes(params.insecure)) {
return {
valid: false,
message: _("Invalid HY2 URL: insecure must be 0 or 1")
};
}
const validObfsTypes = ["none", "salamander"];
if (paramsKeys.includes("obfs") && !validObfsTypes.includes(params.obfs)) {
return {
valid: false,
message: _("Invalid HY2 URL: unsupported obfs type")
};
}
if (paramsKeys.includes("obfs") && params.obfs !== "none" && !params["obfs-password"]) {
return {
valid: false,
message: _(
"Invalid HY2 URL: obfs-password required when obfs is set"
)
};
}
if (paramsKeys.includes("sni") && !params.sni) {
return {
valid: false,
message: _("Invalid HY2 URL: sni cannot be empty")
};
}
}
return { valid: true, message: _("Valid") };
} catch (_e) {
return { valid: false, message: _("Invalid HY2 URL: parsing failed") };
}
}
// src/validators/validateProxyUrl.ts // src/validators/validateProxyUrl.ts
function validateProxyUrl(url) { function validateProxyUrl(url) {
const trimmedUrl = url.trim(); const trimmedUrl = url.trim();
@@ -459,10 +549,13 @@ function validateProxyUrl(url) {
if (/^socks(4|4a|5):\/\//.test(trimmedUrl)) { if (/^socks(4|4a|5):\/\//.test(trimmedUrl)) {
return validateSocksUrl(trimmedUrl); return validateSocksUrl(trimmedUrl);
} }
if (trimmedUrl.startsWith("hysteria2://") || trimmedUrl.startsWith("hy2://")) {
return validateHysteria2Url(trimmedUrl);
}
return { return {
valid: false, valid: false,
message: _( message: _(
"URL must start with vless://, ss://, trojan://, or socks4/5://" "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
) )
}; };
} }
@@ -557,11 +650,11 @@ var PodkopShellMethods = {
]), ]),
getClashApiProxyLatency: async (tag) => callBaseMethod( getClashApiProxyLatency: async (tag) => callBaseMethod(
Podkop.AvailableMethods.CLASH_API, Podkop.AvailableMethods.CLASH_API,
[Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag] [Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag, "5000"]
), ),
getClashApiGroupLatency: async (tag) => callBaseMethod( getClashApiGroupLatency: async (tag) => callBaseMethod(
Podkop.AvailableMethods.CLASH_API, Podkop.AvailableMethods.CLASH_API,
[Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag] [Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag, "10000"]
), ),
setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY, Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
@@ -664,6 +757,30 @@ async function getDashboardSections() {
] ]
}; };
} }
if (section.proxy_config_type === "selector") {
const selector = proxies.find(
(proxy) => proxy.code === `${section[".name"]}-out`
);
const links = section.selector_proxy_links ?? [];
const outbounds = links.map((link, index) => ({
link,
outbound: proxies.find(
(item) => item.code === `${section[".name"]}-${index + 1}-out`
)
})).map((item) => ({
code: item?.outbound?.code || "",
displayName: getProxyUrlName(item.link) || item?.outbound?.value?.name || "",
latency: item?.outbound?.value?.history?.[0]?.delay || 0,
type: item?.outbound?.value?.type || "",
selected: selector?.value?.now === item?.outbound?.code
}));
return {
withTagSelect: true,
code: selector?.code || section[".name"],
displayName: section[".name"],
outbounds
};
}
if (section.proxy_config_type === "urltest") { if (section.proxy_config_type === "urltest") {
const selector = proxies.find( const selector = proxies.find(
(proxy) => proxy.code === `${section[".name"]}-out` (proxy) => proxy.code === `${section[".name"]}-out`
@@ -727,10 +844,18 @@ async function getDashboardSections() {
}; };
} }
// src/podkop/methods/custom/getClashApiSecret.ts
async function getClashApiSecret() {
const sections = await getConfigSections();
const settings = sections.find((section) => section[".type"] === "settings");
return settings?.yacd_secret_key || "";
}
// src/podkop/methods/custom/index.ts // src/podkop/methods/custom/index.ts
var CustomPodkopMethods = { var CustomPodkopMethods = {
getConfigSections, getConfigSections,
getDashboardSections getDashboardSections,
getClashApiSecret
}; };
// src/constants.ts // src/constants.ts
@@ -759,6 +884,7 @@ var ALLOWED_WITH_RUSSIA_INSIDE = [
"hetzner", "hetzner",
"ovh", "ovh",
"hodca", "hodca",
"roblox",
"digitalocean", "digitalocean",
"cloudfront" "cloudfront"
]; ];
@@ -782,6 +908,7 @@ var DOMAIN_LIST_OPTIONS = {
google_ai: "Google AI", google_ai: "Google AI",
google_play: "Google Play", google_play: "Google Play",
hodca: "H.O.D.C.A", hodca: "H.O.D.C.A",
roblox: "Roblox",
hetzner: "Hetzner ASN", hetzner: "Hetzner ASN",
ovh: "OVH ASN", ovh: "OVH ASN",
digitalocean: "Digital Ocean ASN", digitalocean: "Digital Ocean ASN",
@@ -1872,8 +1999,9 @@ async function fetchDashboardSections() {
}); });
} }
async function connectToClashSockets() { async function connectToClashSockets() {
const clashApiSecret = await getClashApiSecret();
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/traffic?token=`, `${getClashWsUrl()}/traffic?token=${clashApiSecret}`,
(msg) => { (msg) => {
const parsedMsg = JSON.parse(msg); const parsedMsg = JSON.parse(msg);
store.set({ store.set({
@@ -1900,7 +2028,7 @@ async function connectToClashSockets() {
} }
); );
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/connections?token=`, `${getClashWsUrl()}/connections?token=${clashApiSecret}`,
(msg) => { (msg) => {
const parsedMsg = JSON.parse(msg); const parsedMsg = JSON.parse(msg);
store.set({ store.set({
@@ -2505,7 +2633,7 @@ async function runSingBoxCheck() {
}, },
{ {
state: data.sing_box_version_ok ? "success" : "error", state: data.sing_box_version_ok ? "success" : "error",
key: _("Sing-box version >= 1.12.4"), key: _("Sing-box version is compatible (newer than 1.12.4)"),
value: "" value: ""
}, },
{ {
@@ -3745,12 +3873,12 @@ async function runSectionsCheck() {
if (selectedProxyDelay) { if (selectedProxyDelay) {
return { return {
success: true, success: true,
latency: `[${selectedOutbound?.code ?? ""}] ${selectedProxyDelay}ms` latency: `[${selectedOutbound?.displayName ?? ""}] ${selectedProxyDelay}ms`
}; };
} }
return { return {
success: false, success: false,
latency: `[${selectedOutbound?.code ?? ""}] ${_("Not responding")}` latency: `[${selectedOutbound?.displayName ?? ""}] ${_("Not responding")}`
}; };
} }
return { return {
@@ -4036,7 +4164,10 @@ async function handleShowSingBoxConfig() {
if (showSingBoxConfig.success) { if (showSingBoxConfig.success) {
ui.showModal( ui.showModal(
_("Show sing-box config"), _("Show sing-box config"),
renderModal(showSingBoxConfig.data, "show_sing_box_config") renderModal(
JSON.stringify(showSingBoxConfig.data, null, 2),
"show_sing_box_config"
)
); );
} else { } else {
logger.error( logger.error(

View File

@@ -15,6 +15,7 @@ function createSectionContent(section) {
o.value("proxy", "Proxy"); o.value("proxy", "Proxy");
o.value("vpn", "VPN"); o.value("vpn", "VPN");
o.value("block", "Block"); o.value("block", "Block");
o.value("exclusion", "Exclusion");
o = section.option( o = section.option(
form.ListValue, form.ListValue,
@@ -23,8 +24,9 @@ function createSectionContent(section) {
_("Select how to configure the proxy"), _("Select how to configure the proxy"),
); );
o.value("url", _("Connection URL")); o.value("url", _("Connection URL"));
o.value("outbound", _("Outbound Config")); o.value("selector", _("Selector"));
o.value("urltest", _("URLTest")); o.value("urltest", _("URLTest"));
o.value("outbound", _("Outbound Config"));
o.default = "url"; o.default = "url";
o.depends("connection_type", "proxy"); o.depends("connection_type", "proxy");
@@ -32,7 +34,7 @@ function createSectionContent(section) {
form.TextValue, form.TextValue,
"proxy_string", "proxy_string",
_("Proxy Configuration URL"), _("Proxy Configuration URL"),
"", _("vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links")
); );
o.depends("proxy_config_type", "url"); o.depends("proxy_config_type", "url");
o.rows = 5; o.rows = 5;
@@ -42,7 +44,6 @@ function createSectionContent(section) {
o.textarea = true; o.textarea = true;
o.rmempty = false; o.rmempty = false;
o.sectionDescriptions = new Map(); o.sectionDescriptions = new Map();
o.placeholder = "vless://uuid@server:port?type=tcp&security=tls#main";
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
// Optional // Optional
if (!value || value.length === 0) { if (!value || value.length === 0) {
@@ -83,11 +84,11 @@ function createSectionContent(section) {
o = section.option( o = section.option(
form.DynamicList, form.DynamicList,
"urltest_proxy_links", "selector_proxy_links",
_("URLTest Proxy Links"), _("Selector Proxy Links"),
_("vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links")
); );
o.depends("proxy_config_type", "urltest"); o.depends("proxy_config_type", "selector");
o.placeholder = "vless://, ss://, trojan://, socks4/5:// links";
o.rmempty = false; o.rmempty = false;
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
// Optional // Optional
@@ -104,6 +105,93 @@ function createSectionContent(section) {
return validation.message; return validation.message;
}; };
o = section.option(
form.DynamicList,
"urltest_proxy_links",
_("URLTest Proxy Links"),
_("vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links")
);
o.depends("proxy_config_type", "urltest");
o.rmempty = false;
o.validate = function (section_id, value) {
// Optional
if (!value || value.length === 0) {
return true;
}
const validation = main.validateProxyUrl(value);
if (validation.valid) {
return true;
}
return validation.message;
};
o = section.option(
form.ListValue,
"urltest_check_interval",
_("URLTest Check Interval"),
_("The interval between connectivity tests")
);
o.value("30s", _("Every 30 seconds"));
o.value("1m", _("Every 1 minute"));
o.value("3m", _("Every 3 minutes"));
o.value("5m", _("Every 5 minutes"));
o.default = "3m";
o.depends("proxy_config_type", "urltest");
o = section.option(
form.Value,
"urltest_tolerance",
_("URLTest Tolerance"),
_("The maximum difference in response times (ms) allowed when comparing servers")
);
o.default = "50";
o.rmempty = false;
o.depends("proxy_config_type", "urltest");
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
const parsed = parseFloat(value);
if (/^[0-9]+$/.test(value) && !isNaN(parsed) && isFinite(parsed) && parsed >= 50 && parsed <= 1000) {
return true;
}
return _('Must be a number in the range of 50 - 1000');
};
o = section.option(
form.Value,
"urltest_testing_url",
_("URLTest Testing URL"),
_("The URL used to test server connectivity")
);
o.value("https://www.gstatic.com/generate_204", "https://www.gstatic.com/generate_204 (Google)");
o.value("https://cp.cloudflare.com/generate_204", "https://cp.cloudflare.com/generate_204 (Cloudflare)");
o.value("https://captive.apple.com", "https://captive.apple.com (Apple)");
o.value("https://connectivity-check.ubuntu.com", "https://connectivity-check.ubuntu.com (Ubuntu)")
o.default = "https://www.gstatic.com/generate_204";
o.rmempty = false;
o.depends("proxy_config_type", "urltest");
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
const validation = main.validateUrl(value);
if (validation.valid) {
return true;
}
return validation.message;
};
o = section.option( o = section.option(
form.Flag, form.Flag,
"enable_udp_over_tcp", "enable_udp_over_tcp",
@@ -381,7 +469,7 @@ function createSectionContent(section) {
); );
o.value("disabled", _("Disabled")); o.value("disabled", _("Disabled"));
o.value("dynamic", _("Dynamic List")); o.value("dynamic", _("Dynamic List"));
o.value("text", _("Text List (comma/space/newline separated)")); o.value("text", _("Text List"));
o.default = "disabled"; o.default = "disabled";
o.rmempty = false; o.rmempty = false;
@@ -554,6 +642,8 @@ function createSectionContent(section) {
); );
o.placeholder = "192.168.1.2 or 192.168.1.0/24"; o.placeholder = "192.168.1.2 or 192.168.1.0/24";
o.rmempty = true; o.rmempty = true;
o.depends("connection_type", "proxy");
o.depends("connection_type", "vpn");
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
// Optional // Optional
if (!value || value.length === 0) { if (!value || value.length === 0) {
@@ -579,6 +669,8 @@ function createSectionContent(section) {
); );
o.default = "0"; o.default = "0";
o.rmempty = false; o.rmempty = false;
o.depends("connection_type", "proxy");
o.depends("connection_type", "vpn");
o = section.option( o = section.option(
form.Value, form.Value,

View File

@@ -240,6 +240,25 @@ function createSettingsContent(section) {
o.default = "0"; o.default = "0";
o.rmempty = false; o.rmempty = false;
o = section.option(
form.Flag,
"enable_yacd_wan_access",
_("Enable YACD WAN Access"),
_("Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."),
);
o.depends("enable_yacd", "1");
o.default = "0";
o.rmempty = false;
o = section.option(
form.Value,
"yacd_secret_key",
_("YACD Secret Key"),
_("Secret key for authenticating remote access to YACD when WAN access is enabled."),
);
o.depends("enable_yacd_wan_access", "1");
o.rmempty = false;
o = section.option( o = section.option(
form.Flag, form.Flag,
"disable_quic", "disable_quic",
@@ -359,6 +378,24 @@ function createSettingsContent(section) {
return true; return true;
}; };
o = section.option(
form.ListValue,
"log_level",
_("Log Level"),
_(
"Select the log level for sing-box",
),
);
o.value("trace", "Trace");
o.value("debug", "Debug");
o.value("info", "Info");
o.value("warn", "Warn");
o.value("error", "Error");
o.value("fatal", "Fatal");
o.value("panic", "Panic");
o.default = "warn";
o.rmempty = false;
o = section.option( o = section.option(
form.Flag, form.Flag,
"exclude_ntp", "exclude_ntp",

View File

@@ -1,15 +1,15 @@
# RU translations for PODKOP package. # RU translations for PODKOP package.
# Copyright (C) 2025 THE PODKOP'S COPYRIGHT HOLDER # Copyright (C) 2026 THE PODKOP'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PODKOP package. # This file is distributed under the same license as the PODKOP package.
# divocat, 2025. # divocatt, 2026.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PODKOP\n" "Project-Id-Version: PODKOP\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-26 14:56+0200\n" "POT-Creation-Date: 2026-01-14 20:21+0200\n"
"PO-Revision-Date: 2025-10-26 14:56+0200\n" "PO-Revision-Date: 2026-01-14 20:21+0200\n"
"Last-Translator: divocat\n" "Last-Translator: divocatt\n"
"Language-Team: none\n" "Language-Team: none\n"
"Language: ru\n" "Language: ru\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -35,6 +35,9 @@ msgstr "Активные соединения"
msgid "Additional marking rules found" msgid "Additional marking rules found"
msgstr "Найдены дополнительные правила маркировки" msgstr "Найдены дополнительные правила маркировки"
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
msgid "Applicable for SOCKS and Shadowsocks proxy" msgid "Applicable for SOCKS and Shadowsocks proxy"
msgstr "Применимо для SOCKS и Shadowsocks прокси" msgstr "Применимо для SOCKS и Shadowsocks прокси"
@@ -206,6 +209,9 @@ msgstr "Включить смешанный прокси-сервер, разр
msgid "Enable YACD" msgid "Enable YACD"
msgstr "Включить YACD" msgstr "Включить YACD"
msgid "Enable YACD WAN Access"
msgstr "Включить доступ YACD WAN"
msgid "Enter complete outbound configuration in JSON format" msgid "Enter complete outbound configuration in JSON format"
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON" msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
@@ -218,6 +224,18 @@ msgstr "Введите доменные имена без протоколов,
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses" msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса" msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
msgid "Every 1 minute"
msgstr "Каждую минуту"
msgid "Every 3 minutes"
msgstr "Каждые 3 минуты"
msgid "Every 30 seconds"
msgstr "Каждые 30 секунд"
msgid "Every 5 minutes"
msgstr "Каждые 5 минут"
msgid "Exclude NTP" msgid "Exclude NTP"
msgstr "Исключить NTP" msgstr "Исключить NTP"
@@ -263,6 +281,45 @@ msgstr "Неверный домен"
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y" msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y" msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
msgid "Invalid HY2 URL: insecure must be 0 or 1"
msgstr "Неверный URL Hysteria2: параметр insecure должен быть 0 или 1"
msgid "Invalid HY2 URL: invalid port number"
msgstr "Неверный URL Hysteria2: неверный номер порта"
msgid "Invalid HY2 URL: missing credentials/server"
msgstr "Неверный URL Hysteria2: отсутствуют учетные данные/сервер"
msgid "Invalid HY2 URL: missing host"
msgstr "Неверный URL Hysteria2: отсутствует хост"
msgid "Invalid HY2 URL: missing host & port"
msgstr "Неверный URL Hysteria2: отсутствуют хост и порт"
msgid "Invalid HY2 URL: missing password"
msgstr "Неверный URL Hysteria2: отсутствует пароль"
msgid "Invalid HY2 URL: missing port"
msgstr "Неверный URL Hysteria2: отсутствует порт"
msgid "Invalid HY2 URL: must not contain spaces"
msgstr "Неверный URL Hysteria2: не должен содержать пробелов"
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
msgstr "Неверный URL Hysteria2: должен начинаться с hysteria2:// или hy2://"
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
msgstr "Неверный URL Hysteria2: требуется obfs-password, когда установлен obfs"
msgid "Invalid HY2 URL: parsing failed"
msgstr "Неверный URL Hysteria2: ошибка разбора"
msgid "Invalid HY2 URL: sni cannot be empty"
msgstr "Неверный URL Hysteria2: sni не может быть пустым"
msgid "Invalid HY2 URL: unsupported obfs type"
msgstr "Неверный URL Hysteria2: неподдерживаемый тип obfs"
msgid "Invalid IP address" msgid "Invalid IP address"
msgstr "Неверный IP-адрес" msgstr "Неверный IP-адрес"
@@ -362,6 +419,9 @@ msgstr "Локальные списки доменов"
msgid "Local Subnet Lists" msgid "Local Subnet Lists"
msgstr "Локальные списки подсетей" msgstr "Локальные списки подсетей"
msgid "Log Level"
msgstr "Уровень логов"
msgid "Main DNS" msgid "Main DNS"
msgstr "Основной DNS" msgstr "Основной DNS"
@@ -374,6 +434,9 @@ msgstr "Порт смешанного прокси"
msgid "Monitored Interfaces" msgid "Monitored Interfaces"
msgstr "Наблюдаемые интерфейсы" msgstr "Наблюдаемые интерфейсы"
msgid "Must be a number in the range of 50 - 1000"
msgstr "Должно быть числом от 50 до 1000"
msgid "Network Interface" msgid "Network Interface"
msgstr "Сетевой интерфейс" msgstr "Сетевой интерфейс"
@@ -482,6 +545,9 @@ msgstr "Запустить диагностику"
msgid "Russia inside restrictions" msgid "Russia inside restrictions"
msgstr "Ограничения Russia inside" msgstr "Ограничения Russia inside"
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
msgstr "Секретный ключ для аутентификации удаленного доступа к YACD при включенном доступе через WAN."
msgid "Sections" msgid "Sections"
msgstr "Секции" msgstr "Секции"
@@ -521,6 +587,9 @@ msgstr "Выберите тип списка для добавления пол
msgid "Select the list type for adding custom subnets" msgid "Select the list type for adding custom subnets"
msgstr "Выберите тип списка для добавления пользовательских подсетей" msgstr "Выберите тип списка для добавления пользовательских подсетей"
msgid "Select the log level for sing-box"
msgstr "Выберите уровень логов для sing-box"
msgid "Select the network interface from which the traffic will originate" msgid "Select the network interface from which the traffic will originate"
msgstr "Выберите сетевой интерфейс, с которого будет исходить трафик" msgstr "Выберите сетевой интерфейс, с которого будет исходить трафик"
@@ -530,6 +599,12 @@ msgstr "Выберите сетевой интерфейс, на который
msgid "Select the WAN interfaces to be monitored" msgid "Select the WAN interfaces to be monitored"
msgstr "Выберите WAN интерфейсы для мониторинга" msgstr "Выберите WAN интерфейсы для мониторинга"
msgid "Selector"
msgstr "Selector"
msgid "Selector Proxy Links"
msgstr "Ссылки прокси для Selector"
msgid "Services info" msgid "Services info"
msgstr "Информация о сервисах" msgstr "Информация о сервисах"
@@ -557,8 +632,8 @@ msgstr "Процесс sing-box запущен"
msgid "Sing-box service exist" msgid "Sing-box service exist"
msgstr "Сервис sing-box существует" msgstr "Сервис sing-box существует"
msgid "Sing-box version >= 1.12.4" msgid "Sing-box version is compatible (newer than 1.12.4)"
msgstr "Версия sing-box >= 1.12.4" msgstr "Версия Sing-box совместима (новее 1.12.4)"
msgid "Source Network Interface" msgid "Source Network Interface"
msgstr "Сетевой интерфейс источника" msgstr "Сетевой интерфейс источника"
@@ -602,12 +677,18 @@ msgstr "Тестирование задержки"
msgid "Text List" msgid "Text List"
msgstr "Текстовый список" msgstr "Текстовый список"
msgid "Text List (comma/space/newline separated)"
msgstr "Текстовый список (через запятую, пробел или новую строку)"
msgid "The DNS server used to look up the IP address of an upstream DNS server" msgid "The DNS server used to look up the IP address of an upstream DNS server"
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера" msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
msgid "The interval between connectivity tests"
msgstr "Интервал между тестами подключения"
msgid "The maximum difference in response times (ms) allowed when comparing servers"
msgstr "Максимально допустимая разница во времени отклика (мс) при сравнении серверов"
msgid "The URL used to test server connectivity"
msgstr "URL-адрес, используемый для проверки подключения к серверу"
msgid "Time in seconds for DNS record caching (default: 60)" msgid "Time in seconds for DNS record caching (default: 60)"
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)" msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
@@ -641,8 +722,8 @@ msgstr "Неизвестная ошибка"
msgid "Uplink" msgid "Uplink"
msgstr "Исходящий" msgstr "Исходящий"
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://" msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
msgstr "URL должен начинаться с vless://, ss://, trojan:// или socks4/5://" msgstr "URL должен начинаться с vless://, ss://, trojan://, socks4/5:// или hysteria2:// hy2://"
msgid "URL must use one of the following protocols:" msgid "URL must use one of the following protocols:"
msgstr "URL должен использовать один из следующих протоколов:" msgstr "URL должен использовать один из следующих протоколов:"
@@ -650,9 +731,18 @@ msgstr "URL должен использовать один из следующи
msgid "URLTest" msgid "URLTest"
msgstr "URLTest" msgstr "URLTest"
msgid "URLTest Check Interval"
msgstr "Интервал проверки URLTest"
msgid "URLTest Proxy Links" msgid "URLTest Proxy Links"
msgstr "Ссылки прокси для URLTest" msgstr "Ссылки прокси для URLTest"
msgid "URLTest Testing URL"
msgstr "URLTest ссылка для проверки"
msgid "URLTest Tolerance"
msgstr "URLTest допустимое отклонение"
msgid "User Domain List Type" msgid "User Domain List Type"
msgstr "Тип пользовательского списка доменов" msgstr "Тип пользовательского списка доменов"
@@ -683,11 +773,17 @@ msgstr "Посмотреть логи"
msgid "Visit Wiki" msgid "Visit Wiki"
msgstr "Перейти в wiki" msgstr "Перейти в wiki"
msgid "vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links"
msgstr ""
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed." msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
msgstr "Предупреждение: %s нельзя использовать вместе с %s. Предыдущие варианты были удалены." msgstr "Предупреждение: %s нельзя использовать вместе с %s. Предыдущие варианты были удалены."
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection." msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных." msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
msgid "YACD Secret Key"
msgstr "Секретный ключ YACD"
msgid "You can select Output Network Interface, by default autodetect" msgid "You can select Output Network Interface, by default autodetect"
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически." msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."

View File

@@ -1,38 +1,38 @@
# SOME DESCRIPTIVE TITLE. # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2025 THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2026 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PODKOP package. # This file is distributed under the same license as the PODKOP package.
# divocat <divocatt@gmail.com>, 2025. # divocatt <210179590+divocatt@users.noreply.github.com>, 2026.
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PODKOP\n" "Project-Id-Version: PODKOP\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-26 12:56+0200\n" "POT-Creation-Date: 2026-01-14 18:21+0200\n"
"PO-Revision-Date: 2025-10-26 12:56+0200\n" "PO-Revision-Date: 2026-01-14 18:21+0200\n"
"Last-Translator: divocat <divocatt@gmail.com>\n" "Last-Translator: divocatt <210179590+divocatt@users.noreply.github.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: src/podkop/tabs/dashboard/initController.ts:342 #: src/podkop/tabs/dashboard/initController.ts:345
msgid "✔ Enabled" msgid "✔ Enabled"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:353 #: src/podkop/tabs/dashboard/initController.ts:356
msgid "✔ Running" msgid "✔ Running"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:343 #: src/podkop/tabs/dashboard/initController.ts:346
msgid "✘ Disabled" msgid "✘ Disabled"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:354 #: src/podkop/tabs/dashboard/initController.ts:357
msgid "✘ Stopped" msgid "✘ Stopped"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:304 #: src/podkop/tabs/dashboard/initController.ts:307
msgid "Active Connections" msgid "Active Connections"
msgstr "" msgstr ""
@@ -40,15 +40,19 @@ msgstr ""
msgid "Additional marking rules found" msgid "Additional marking rules found"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:198
msgid "Applicable for SOCKS and Shadowsocks proxy" msgid "Applicable for SOCKS and Shadowsocks proxy"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:356 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:443
msgid "At least one valid domain must be specified. Comments-only content is not allowed." msgid "At least one valid domain must be specified. Comments-only content is not allowed."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:437 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:524
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed." msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
msgstr "" msgstr ""
@@ -72,11 +76,11 @@ msgstr ""
msgid "Browser is using FakeIP correctly" msgid "Browser is using FakeIP correctly"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:329 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:348
msgid "Cache File Path" msgid "Cache File Path"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:343 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:362
msgid "Cache file path cannot be empty" msgid "Cache file path cannot be empty"
msgstr "" msgstr ""
@@ -115,11 +119,11 @@ msgstr ""
msgid "Close" msgid "Close"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:211 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:298
msgid "Community Lists" msgid "Community Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:316 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:335
msgid "Config File Path" msgid "Config File Path"
msgstr "" msgstr ""
@@ -175,16 +179,16 @@ msgstr ""
msgid "Disable autostart" msgid "Disable autostart"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:265
msgid "Disable QUIC" msgid "Disable QUIC"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:266
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming" msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:302 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:389
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:382 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:469
msgid "Disabled" msgid "Disabled"
msgstr "" msgstr ""
@@ -192,17 +196,17 @@ msgstr ""
msgid "DNS on router" msgid "DNS on router"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:179 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
msgid "DNS over HTTPS (DoH)" msgid "DNS over HTTPS (DoH)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:180 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:267
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
msgid "DNS over TLS (DoT)" msgid "DNS over TLS (DoT)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:176 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:263
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
msgid "DNS Protocol Type" msgid "DNS Protocol Type"
msgstr "" msgstr ""
@@ -211,7 +215,7 @@ msgstr ""
msgid "DNS Rewrite TTL" msgid "DNS Rewrite TTL"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:189 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:276
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
msgid "DNS Server" msgid "DNS Server"
msgstr "" msgstr ""
@@ -224,16 +228,16 @@ msgstr ""
msgid "Do not panic, everything can be fixed, just..." msgid "Do not panic, everything can be fixed, just..."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:166 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:253
msgid "Domain Resolver" msgid "Domain Resolver"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:307 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:326
msgid "Dont Touch My DHCP!" msgid "Dont Touch My DHCP!"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:238 #: src/podkop/tabs/dashboard/initController.ts:241
#: src/podkop/tabs/dashboard/initController.ts:272 #: src/podkop/tabs/dashboard/initController.ts:275
msgid "Downlink" msgid "Downlink"
msgstr "" msgstr ""
@@ -241,21 +245,21 @@ msgstr ""
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:269 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:288
msgid "Download Lists via Proxy/VPN" msgid "Download Lists via Proxy/VPN"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:278 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:297
msgid "Download Lists via specific proxy section" msgid "Download Lists via specific proxy section"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:270 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:289
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:279 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:298
msgid "Downloading all lists via specific Proxy/VPN" msgid "Downloading all lists via specific Proxy/VPN"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:303 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:390
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:383 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:470
msgid "Dynamic List" msgid "Dynamic List"
msgstr "" msgstr ""
@@ -263,11 +267,11 @@ msgstr ""
msgid "Enable autostart" msgid "Enable autostart"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:167 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:254
msgid "Enable built-in DNS resolver for domains handled by this section" msgid "Enable built-in DNS resolver for domains handled by this section"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:575 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:662
msgid "Enable Mixed Proxy" msgid "Enable Mixed Proxy"
msgstr "" msgstr ""
@@ -275,7 +279,7 @@ msgstr ""
msgid "Enable Output Network Interface" msgid "Enable Output Network Interface"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:576 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:663
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies" msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
msgstr "" msgstr ""
@@ -283,27 +287,47 @@ msgstr ""
msgid "Enable YACD" msgid "Enable YACD"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
msgid "Enable YACD WAN Access"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
msgid "Enter complete outbound configuration in JSON format" msgid "Enter complete outbound configuration in JSON format"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:338 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:425
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //" msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:312 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:399
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com" msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:392 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:479
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses" msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:365 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:137
msgid "Every 1 minute"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:138
msgid "Every 3 minutes"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:136
msgid "Every 30 seconds"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:139
msgid "Every 5 minutes"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:402
msgid "Exclude NTP" msgid "Exclude NTP"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:403
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN" msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
msgstr "" msgstr ""
@@ -321,11 +345,11 @@ msgid "Failed to execute!"
msgstr "" msgstr ""
#: src/podkop/methods/custom/getDashboardSections.ts:117 #: src/podkop/methods/custom/getDashboardSections.ts:117
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:58 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:59
msgid "Fastest" msgid "Fastest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:550 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:637
msgid "Fully Routed IPs" msgid "Fully Routed IPs"
msgstr "" msgstr ""
@@ -366,6 +390,58 @@ msgstr ""
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y" msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
msgstr "" msgstr ""
#: src/validators/validateHysteriaUrl.ts:76
msgid "Invalid HY2 URL: insecure must be 0 or 1"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:62
msgid "Invalid HY2 URL: invalid port number"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:32
msgid "Invalid HY2 URL: missing credentials/server"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:49
msgid "Invalid HY2 URL: missing host"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:43
msgid "Invalid HY2 URL: missing host & port"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:38
msgid "Invalid HY2 URL: missing password"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:53
msgid "Invalid HY2 URL: missing port"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:19
msgid "Invalid HY2 URL: must not contain spaces"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:12
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:99
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:115
msgid "Invalid HY2 URL: parsing failed"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:108
msgid "Invalid HY2 URL: sni cannot be empty"
msgstr ""
#: src/validators/validateHysteriaUrl.ts:88
msgid "Invalid HY2 URL: unsupported obfs type"
msgstr ""
#: src/validators/validateIp.ts:11 #: src/validators/validateIp.ts:11
msgid "Invalid IP address" msgid "Invalid IP address"
msgstr "" msgstr ""
@@ -466,7 +542,8 @@ msgstr ""
msgid "Invalid Trojan URL: parsing failed" msgid "Invalid Trojan URL: parsing failed"
msgstr "" msgstr ""
#: src/validators/validateUrl.ts:18 #: src/validators/validateUrl.ts:8
#: src/validators/validateUrl.ts:31
msgid "Invalid URL format" msgid "Invalid URL format"
msgstr "" msgstr ""
@@ -486,27 +563,31 @@ msgstr ""
msgid "Latest" msgid "Latest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:276
msgid "List Update Frequency" msgid "List Update Frequency"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:458 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:545
msgid "Local Domain Lists" msgid "Local Domain Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:568
msgid "Local Subnet Lists" msgid "Local Subnet Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:384
msgid "Log Level"
msgstr ""
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:72 #: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:72
msgid "Main DNS" msgid "Main DNS"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:308 #: src/podkop/tabs/dashboard/initController.ts:311
msgid "Memory Usage" msgid "Memory Usage"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:586 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:673
msgid "Mixed Proxy Port" msgid "Mixed Proxy Port"
msgstr "" msgstr ""
@@ -514,7 +595,11 @@ msgstr ""
msgid "Monitored Interfaces" msgid "Monitored Interfaces"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:120 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:163
msgid "Must be a number in the range of 50 - 1000"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:207
msgid "Network Interface" msgid "Network Interface"
msgstr "" msgstr ""
@@ -526,9 +611,9 @@ msgstr ""
msgid "Not implement yet" msgid "Not implement yet"
msgstr "" msgstr ""
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:74 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:75
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:80 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:81
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:99 #: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:100
msgid "Not responding" msgid "Not responding"
msgstr "" msgstr ""
@@ -544,7 +629,7 @@ msgstr ""
msgid "Operation timed out" msgid "Operation timed out"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:26 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:28
msgid "Outbound Config" msgid "Outbound Config"
msgstr "" msgstr ""
@@ -564,15 +649,15 @@ msgstr ""
msgid "Path cannot be empty" msgid "Path cannot be empty"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:347 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
msgid "Path must be absolute (start with /)" msgid "Path must be absolute (start with /)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:356 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:375
msgid "Path must contain at least one directory (like /tmp/cache.db)" msgid "Path must contain at least one directory (like /tmp/cache.db)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:351 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:370
msgid "Path must end with cache.db" msgid "Path must end with cache.db"
msgstr "" msgstr ""
@@ -584,7 +669,7 @@ msgstr ""
msgid "Pending" msgid "Pending"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:340 #: src/podkop/tabs/dashboard/initController.ts:343
msgid "Podkop" msgid "Podkop"
msgstr "" msgstr ""
@@ -592,11 +677,11 @@ msgstr ""
msgid "Podkop Settings" msgid "Podkop Settings"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:308 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:327
msgid "Podkop will not modify your DHCP configuration" msgid "Podkop will not modify your DHCP configuration"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:34 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:35
msgid "Proxy Configuration URL" msgid "Proxy Configuration URL"
msgstr "" msgstr ""
@@ -608,15 +693,15 @@ msgstr ""
msgid "Proxy traffic is routed via FakeIP" msgid "Proxy traffic is routed via FakeIP"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:332
msgid "Regional options cannot be used together" msgid "Regional options cannot be used together"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:591
msgid "Remote Domain Lists" msgid "Remote Domain Lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:527 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:614
msgid "Remote Subnet Lists" msgid "Remote Subnet Lists"
msgstr "" msgstr ""
@@ -632,7 +717,7 @@ msgstr ""
msgid "Router DNS is routed through sing-box" msgid "Router DNS is routed through sing-box"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:376 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:413
msgid "Routing Excluded IPs" msgid "Routing Excluded IPs"
msgstr "" msgstr ""
@@ -664,15 +749,19 @@ msgstr ""
msgid "Run Diagnostic" msgid "Run Diagnostic"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:351
msgid "Russia inside restrictions" msgid "Russia inside restrictions"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
msgid "Sections" msgid "Sections"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:212 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299
msgid "Select a predefined list for routing" msgid "Select a predefined list for routing"
msgstr "" msgstr ""
@@ -684,7 +773,7 @@ msgstr ""
msgid "Select DNS protocol to use" msgid "Select DNS protocol to use"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:258 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:277
msgid "Select how often the domain or subnet lists are updated automatically" msgid "Select how often the domain or subnet lists are updated automatically"
msgstr "" msgstr ""
@@ -692,35 +781,39 @@ msgstr ""
msgid "Select how to configure the proxy" msgid "Select how to configure the proxy"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:121 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:208
msgid "Select network interface for VPN connection" msgid "Select network interface for VPN connection"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:190 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:277
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
msgid "Select or enter DNS server address" msgid "Select or enter DNS server address"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:330 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:349
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing" msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:317 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:336
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing" msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:177 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264
msgid "Select the DNS protocol type for the domain resolver" msgid "Select the DNS protocol type for the domain resolver"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:300 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:387
msgid "Select the list type for adding custom domains" msgid "Select the list type for adding custom domains"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:380 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:467
msgid "Select the list type for adding custom subnets" msgid "Select the list type for adding custom subnets"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:385
msgid "Select the log level for sing-box"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:90 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:90
msgid "Select the network interface from which the traffic will originate" msgid "Select the network interface from which the traffic will originate"
msgstr "" msgstr ""
@@ -733,7 +826,15 @@ msgstr ""
msgid "Select the WAN interfaces to be monitored" msgid "Select the WAN interfaces to be monitored"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:337 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:26
msgid "Selector"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
msgid "Selector Proxy Links"
msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:340
msgid "Services info" msgid "Services info"
msgstr "" msgstr ""
@@ -746,7 +847,7 @@ msgstr ""
msgid "Show sing-box config" msgid "Show sing-box config"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:351 #: src/podkop/tabs/dashboard/initController.ts:354
msgid "Sing-box" msgid "Sing-box"
msgstr "" msgstr ""
@@ -771,31 +872,31 @@ msgid "Sing-box service exist"
msgstr "" msgstr ""
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67 #: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
msgid "Sing-box version >= 1.12.4" msgid "Sing-box version is compatible (newer than 1.12.4)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
msgid "Source Network Interface" msgid "Source Network Interface"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:377 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:414
msgid "Specify a local IP address to be excluded from routing" msgid "Specify a local IP address to be excluded from routing"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:551 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:638
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route" msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:505 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:592
msgid "Specify remote URLs to download and use domain lists" msgid "Specify remote URLs to download and use domain lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:528 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:615
msgid "Specify remote URLs to download and use subnet lists" msgid "Specify remote URLs to download and use subnet lists"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:459 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:546
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:482 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:569
msgid "Specify the path to the list file located on the router filesystem" msgid "Specify the path to the list file located on the router filesystem"
msgstr "" msgstr ""
@@ -811,7 +912,7 @@ msgstr ""
msgid "Successfully copied!" msgid "Successfully copied!"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:301 #: src/podkop/tabs/dashboard/initController.ts:304
msgid "System info" msgid "System info"
msgstr "" msgstr ""
@@ -827,27 +928,36 @@ msgstr ""
msgid "Test latency" msgid "Test latency"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:304 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:471
msgid "Text List" msgid "Text List"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:384
msgid "Text List (comma/space/newline separated)"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
msgid "The DNS server used to look up the IP address of an upstream DNS server" msgid "The DNS server used to look up the IP address of an upstream DNS server"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:134
msgid "The interval between connectivity tests"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:147
msgid "The maximum difference in response times (ms) allowed when comparing servers"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:170
msgid "The URL used to test server connectivity"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
msgid "Time in seconds for DNS record caching (default: 60)" msgid "Time in seconds for DNS record caching (default: 60)"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:235 #: src/podkop/tabs/dashboard/initController.ts:238
msgid "Traffic" msgid "Traffic"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:265 #: src/podkop/tabs/dashboard/initController.ts:268
msgid "Traffic Total" msgid "Traffic Total"
msgstr "" msgstr ""
@@ -863,12 +973,12 @@ msgstr ""
msgid "TTL value cannot be empty" msgid "TTL value cannot be empty"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:181 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:268
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
msgid "UDP (Unprotected DNS)" msgid "UDP (Unprotected DNS)"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:197
msgid "UDP over TCP" msgid "UDP over TCP"
msgstr "" msgstr ""
@@ -886,16 +996,16 @@ msgstr ""
msgid "Unknown error" msgid "Unknown error"
msgstr "" msgstr ""
#: src/podkop/tabs/dashboard/initController.ts:237 #: src/podkop/tabs/dashboard/initController.ts:240
#: src/podkop/tabs/dashboard/initController.ts:268 #: src/podkop/tabs/dashboard/initController.ts:271
msgid "Uplink" msgid "Uplink"
msgstr "" msgstr ""
#: src/validators/validateProxyUrl.ts:29 #: src/validators/validateProxyUrl.ts:37
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://" msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
msgstr "" msgstr ""
#: src/validators/validateUrl.ts:13 #: src/validators/validateUrl.ts:17
msgid "URL must use one of the following protocols:" msgid "URL must use one of the following protocols:"
msgstr "" msgstr ""
@@ -903,31 +1013,43 @@ msgstr ""
msgid "URLTest" msgid "URLTest"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:133
msgid "URLTest Check Interval"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
msgid "URLTest Proxy Links" msgid "URLTest Proxy Links"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:169
msgid "URLTest Testing URL"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:146
msgid "URLTest Tolerance"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:386
msgid "User Domain List Type" msgid "User Domain List Type"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:398
msgid "User Domains" msgid "User Domains"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:337 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:424
msgid "User Domains List" msgid "User Domains List"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:379 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:466
msgid "User Subnet List Type" msgid "User Subnet List Type"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:478
msgid "User Subnets" msgid "User Subnets"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:417 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504
msgid "User Subnets List" msgid "User Subnets List"
msgstr "" msgstr ""
@@ -935,6 +1057,7 @@ msgstr ""
#: src/validators/validateDns.ts:18 #: src/validators/validateDns.ts:18
#: src/validators/validateDomain.ts:13 #: src/validators/validateDomain.ts:13
#: src/validators/validateDomain.ts:30 #: src/validators/validateDomain.ts:30
#: src/validators/validateHysteriaUrl.ts:113
#: src/validators/validateIp.ts:8 #: src/validators/validateIp.ts:8
#: src/validators/validateOutboundJson.ts:7 #: src/validators/validateOutboundJson.ts:7
#: src/validators/validatePath.ts:16 #: src/validators/validatePath.ts:16
@@ -942,13 +1065,13 @@ msgstr ""
#: src/validators/validateSocksUrl.ts:80 #: src/validators/validateSocksUrl.ts:80
#: src/validators/validateSubnet.ts:38 #: src/validators/validateSubnet.ts:38
#: src/validators/validateTrojanUrl.ts:59 #: src/validators/validateTrojanUrl.ts:59
#: src/validators/validateUrl.ts:16 #: src/validators/validateUrl.ts:28
#: src/validators/validateVlessUrl.ts:108 #: src/validators/validateVlessUrl.ts:108
msgid "Valid" msgid "Valid"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:370 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:457
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:449 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:536
msgid "Validation errors:" msgid "Validation errors:"
msgstr "" msgstr ""
@@ -961,14 +1084,24 @@ msgstr ""
msgid "Visit Wiki" msgid "Visit Wiki"
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:247 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:36
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:88
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
msgid "vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:334
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed." msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:353
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection." msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
msgstr "" msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:256
msgid "YACD Secret Key"
msgstr ""
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127 #: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
msgid "You can select Output Network Interface, by default autodetect" msgid "You can select Output Network Interface, by default autodetect"
msgstr "" msgstr ""

View File

@@ -16,6 +16,7 @@ config settings 'settings'
option dont_touch_dhcp '0' option dont_touch_dhcp '0'
option config_path '/etc/sing-box/config.json' option config_path '/etc/sing-box/config.json'
option cache_path '/tmp/sing-box/cache.db' option cache_path '/tmp/sing-box/cache.db'
option log_level 'warn'
option exclude_ntp '0' option exclude_ntp '0'
option shutdown_correctly '0' option shutdown_correctly '0'
#list routing_excluded_ips '192.168.1.3' #list routing_excluded_ips '192.168.1.3'

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@ TMP_RULESET_FOLDER="$TMP_SING_BOX_FOLDER/rulesets"
CLOUDFLARE_OCTETS="8.47 162.159 188.114" # Endpoints https://github.com/ampetelin/warp-endpoint-checker CLOUDFLARE_OCTETS="8.47 162.159 188.114" # Endpoints https://github.com/ampetelin/warp-endpoint-checker
JQ_REQUIRED_VERSION="1.7.1" JQ_REQUIRED_VERSION="1.7.1"
COREUTILS_BASE64_REQUIRED_VERSION="9.7" COREUTILS_BASE64_REQUIRED_VERSION="9.7"
RT_TABLE_NAME="podkop"
## nft ## nft
NFT_TABLE_NAME="PodkopTable" NFT_TABLE_NAME="PodkopTable"
@@ -19,11 +20,11 @@ NFT_LOCALV4_SET_NAME="localv4"
NFT_COMMON_SET_NAME="podkop_subnets" NFT_COMMON_SET_NAME="podkop_subnets"
NFT_DISCORD_SET_NAME="podkop_discord_subnets" NFT_DISCORD_SET_NAME="podkop_discord_subnets"
NFT_INTERFACE_SET_NAME="interfaces" NFT_INTERFACE_SET_NAME="interfaces"
NFT_FAKEIP_MARK="0x00100000"
NFT_OUTBOUND_MARK="0x00200000"
## sing-box ## sing-box
SB_REQUIRED_VERSION="1.12.0" SB_REQUIRED_VERSION="1.12.0"
# Log
SB_DEFAULT_LOG_LEVEL="warn"
# DNS # DNS
SB_DNS_SERVER_TAG="dns-server" SB_DNS_SERVER_TAG="dns-server"
SB_FAKEIP_DNS_SERVER_TAG="fakeip-server" SB_FAKEIP_DNS_SERVER_TAG="fakeip-server"
@@ -38,7 +39,6 @@ SB_TPROXY_INBOUND_PORT=1602
SB_DNS_INBOUND_TAG="dns-in" SB_DNS_INBOUND_TAG="dns-in"
SB_DNS_INBOUND_ADDRESS="127.0.0.42" SB_DNS_INBOUND_ADDRESS="127.0.0.42"
SB_DNS_INBOUND_PORT=53 SB_DNS_INBOUND_PORT=53
SB_MIXED_INBOUND_ADDRESS="0.0.0.0" # TODO(ampetelin): maybe to determine address?
SB_SERVICE_MIXED_INBOUND_TAG="service-mixed-in" SB_SERVICE_MIXED_INBOUND_TAG="service-mixed-in"
SB_SERVICE_MIXED_INBOUND_ADDRESS="127.0.0.1" SB_SERVICE_MIXED_INBOUND_ADDRESS="127.0.0.1"
SB_SERVICE_MIXED_INBOUND_PORT=4534 SB_SERVICE_MIXED_INBOUND_PORT=4534
@@ -46,23 +46,21 @@ SB_SERVICE_MIXED_INBOUND_PORT=4534
SB_DIRECT_OUTBOUND_TAG="direct-out" SB_DIRECT_OUTBOUND_TAG="direct-out"
# Route # Route
SB_REJECT_RULE_TAG="reject-rule-tag" SB_REJECT_RULE_TAG="reject-rule-tag"
SB_EXCLUSION_RULE_TAG="exclusion-rule-tag"
# Experimental # Experimental
SB_CLASH_API_CONTROLLER="0.0.0.0:9090" SB_CLASH_API_CONTROLLER_PORT=9090
## Lists ## Lists
GITHUB_RAW_URL="https://raw.githubusercontent.com/itdoginfo/allow-domains/main" GITHUB_RAW_URL="https://raw.githubusercontent.com/itdoginfo/allow-domains/main"
SRS_MAIN_URL="https://github.com/itdoginfo/allow-domains/releases/latest/download" SRS_MAIN_URL="https://github.com/itdoginfo/allow-domains/releases/latest/download"
DOMAINS_RU_INSIDE="${GITHUB_RAW_URL}/Russia/inside-dnsmasq-nfset.lst"
DOMAINS_RU_OUTSIDE="${GITHUB_RAW_URL}/Russia/outside-dnsmasq-nfset.lst"
DOMAINS_UA="${GITHUB_RAW_URL}/Ukraine/inside-dnsmasq-nfset.lst"
DOMAINS_YOUTUBE="${GITHUB_RAW_URL}/Services/youtube.lst"
SUBNETS_TWITTER="${GITHUB_RAW_URL}/Subnets/IPv4/twitter.lst" SUBNETS_TWITTER="${GITHUB_RAW_URL}/Subnets/IPv4/twitter.lst"
SUBNETS_META="${GITHUB_RAW_URL}/Subnets/IPv4/meta.lst" SUBNETS_META="${GITHUB_RAW_URL}/Subnets/IPv4/meta.lst"
SUBNETS_DISCORD="${GITHUB_RAW_URL}/Subnets/IPv4/discord.lst" SUBNETS_DISCORD="${GITHUB_RAW_URL}/Subnets/IPv4/discord.lst"
SUBNETS_ROBLOX="${GITHUB_RAW_URL}/Subnets/IPv4/roblox.lst"
SUBNETS_TELERAM="${GITHUB_RAW_URL}/Subnets/IPv4/telegram.lst" SUBNETS_TELERAM="${GITHUB_RAW_URL}/Subnets/IPv4/telegram.lst"
SUBNETS_CLOUDFLARE="${GITHUB_RAW_URL}/Subnets/IPv4/cloudflare.lst" SUBNETS_CLOUDFLARE="${GITHUB_RAW_URL}/Subnets/IPv4/cloudflare.lst"
SUBNETS_HETZNER="${GITHUB_RAW_URL}/Subnets/IPv4/hetzner.lst" SUBNETS_HETZNER="${GITHUB_RAW_URL}/Subnets/IPv4/hetzner.lst"
SUBNETS_OVH="${GITHUB_RAW_URL}/Subnets/IPv4/ovh.lst" SUBNETS_OVH="${GITHUB_RAW_URL}/Subnets/IPv4/ovh.lst"
SUBNETS_DIGITALOCEAN="${GITHUB_RAW_URL}/Subnets/IPv4/digitalocean.lst" SUBNETS_DIGITALOCEAN="${GITHUB_RAW_URL}/Subnets/IPv4/digitalocean.lst"
SUBNETS_CLOUDFRONT="${GITHUB_RAW_URL}/Subnets/IPv4/cloudfront.lst" SUBNETS_CLOUDFRONT="${GITHUB_RAW_URL}/Subnets/IPv4/cloudfront.lst"
COMMUNITY_SERVICES="russia_inside russia_outside ukraine_inside geoblock block porn news anime youtube hdrezka tiktok google_ai google_play hodca discord meta twitter cloudflare cloudfront digitalocean hetzner ovh telegram" COMMUNITY_SERVICES="russia_inside russia_outside ukraine_inside geoblock block porn news anime youtube hdrezka tiktok google_ai google_play hodca discord meta twitter cloudflare cloudfront digitalocean hetzner ovh telegram roblox"

View File

@@ -105,37 +105,6 @@ get_domain_resolver_tag() {
echo "$section-$postfix" echo "$section-$postfix"
} }
# Constructs and returns a ruleset tag using section, name, optional type, and a fixed postfix
get_ruleset_tag() {
local section="$1"
local name="$2"
local type="$3"
local postfix="ruleset"
if [ -n "$type" ]; then
echo "$section-$name-$type-$postfix"
else
echo "$section-$name-$postfix"
fi
}
# Determines the ruleset format based on the file extension (json → source, srs → binary)
get_ruleset_format_by_file_extension() {
local file_extension="$1"
local format
case "$file_extension" in
json) format="source" ;;
srs) format="binary" ;;
*)
log "Unsupported file extension: .$file_extension" "error"
return 1
;;
esac
echo "$format"
}
# Converts a comma-separated string into a JSON array string # Converts a comma-separated string into a JSON array string
comma_string_to_json_array() { comma_string_to_json_array() {
local input="$1" local input="$1"
@@ -156,6 +125,12 @@ url_decode() {
printf '%b' "$(echo "$encoded" | sed 's/+/ /g; s/%/\\x/g')" printf '%b' "$(echo "$encoded" | sed 's/+/ /g; s/%/\\x/g')"
} }
# Returns the scheme (protocol) part of a URL
url_get_scheme() {
local url="$1"
echo "${url%%://*}"
}
# Extracts the userinfo (username[:password]) part from a URL # Extracts the userinfo (username[:password]) part from a URL
url_get_userinfo() { url_get_userinfo() {
local url="$1" local url="$1"
@@ -165,13 +140,23 @@ url_get_userinfo() {
# Extracts the host part from a URL # Extracts the host part from a URL
url_get_host() { url_get_host() {
local url="$1" local url="$1"
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#\([:/].*\|$\)##p'
url="${url#*://}"
url="${url#*@}"
url="${url%%[/?#]*}"
echo "${url%%:*}"
} }
# Extracts the port number from a URL # Extracts the port number from a URL
url_get_port() { url_get_port() {
local url="$1" local url="$1"
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#^[^/]*:\([0-9][0-9]*\).*#\1#p'
url="${url#*://}"
url="${url#*@}"
url="${url%%[/?#]*}"
[[ "$url" == *:* ]] && echo "${url#*:}" || echo ""
} }
# Extracts the path from a URL (without query or fragment; returns "/" if empty) # Extracts the path from a URL (without query or fragment; returns "/" if empty)
@@ -268,25 +253,6 @@ migration_rename_config_key() {
fi fi
} }
# Download URL content directly
download_to_stream() {
local url="$1"
local http_proxy_address="$2"
local retries="${3:-3}"
local wait="${4:-2}"
for attempt in $(seq 1 "$retries"); do
if [ -n "$http_proxy_address" ]; then
http_proxy="http://$http_proxy_address" https_proxy="http://$http_proxy_address" wget -qO- "$url" | sed 's/\r$//' && break
else
wget -qO- "$url" | sed 's/\r$//' && break
fi
log "Attempt $attempt/$retries to download $url failed" "warn"
sleep "$wait"
done
}
# Download URL to file # Download URL to file
download_to_file() { download_to_file() {
local url="$1" local url="$1"
@@ -305,29 +271,17 @@ download_to_file() {
log "Attempt $attempt/$retries to download $url failed" "warn" log "Attempt $attempt/$retries to download $url failed" "warn"
sleep "$wait" sleep "$wait"
done done
if grep -q $'\r' "$filepath"; then
log "Downloaded file has Windows line endings (CRLF). Converting to Unix (LF)"
sed -i 's/\r$//' "$filepath"
fi
} }
# Decompiles a sing-box SRS binary file into a JSON ruleset file # Converts Windows-style line endings (CRLF) to Unix-style (LF)
decompile_srs_file() { convert_crlf_to_lf() {
local binary_filepath="$1" local filepath="$1"
local output_filepath="$2"
log "Decompiling $binary_filepath to $output_filepath" "debug" if grep -q $'\r' "$filepath"; then
log "File '$filepath' contains CRLF line endings. Converting to LF..." "debug"
if ! file_exists "$binary_filepath"; then local tmpfile
log "File $binary_filepath not found" "error" tmpfile=$(mktemp)
return 1 tr -d '\r' < "$filepath" > "$tmpfile" && mv "$tmpfile" "$filepath" || rm -f "$tmpfile"
fi
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
if [[ $? -ne 0 ]]; then
log "Decompilation command failed for $binary_filepath" "error"
return 1
fi fi
} }
@@ -399,4 +353,4 @@ parse_domain_or_subnet_file_to_comma_string() {
done < "$filepath" done < "$filepath"
echo "$result" echo "$result"
} }

View File

@@ -18,7 +18,9 @@ nolog() {
local timestamp local timestamp
timestamp=$(date +"%Y-%m-%d %H:%M:%S") timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${COLOR_CYAN}[$timestamp]${COLOR_RESET} ${COLOR_GREEN}$message${COLOR_RESET}" if [ -t 1 ]; then
echo -e "${COLOR_CYAN}[$timestamp]${COLOR_RESET} ${COLOR_GREEN}$message${COLOR_RESET}"
fi
} }
echolog() { echolog() {

View File

@@ -27,4 +27,44 @@ nft_add_set_elements() {
local elements="$3" local elements="$3"
nft add element inet "$table" "$set" "{ $elements }" nft add element inet "$table" "$set" "{ $elements }"
}
nft_add_set_elements_from_file_chunked() {
local filepath="$1"
local nft_table_name="$2"
local nft_set_name="$3"
local chunk_size="${4:-5000}"
local array count
count=0
while IFS= read -r line; do
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -z "$line" ] && continue
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
continue
fi
if [ -z "$array" ]; then
array="$line"
else
array="$array,$line"
fi
count=$((count + 1))
if [ "$count" = "$chunk_size" ]; then
log "Adding $count elements to nft set $nft_set_name" "debug"
nft_add_set_elements "$nft_table_name" "$nft_set_name" "$array"
array=""
count=0
fi
done < "$filepath"
if [ -n "$array" ]; then
log "Adding $count elements to nft set $nft_set_name" "debug"
nft_add_set_elements "$nft_table_name" "$nft_set_name" "$array"
fi
} }

View File

@@ -0,0 +1,180 @@
# Constructs and returns a ruleset tag using section, name, optional type, and a fixed postfix
get_ruleset_tag() {
local section="$1"
local name="$2"
local type="$3"
local postfix="ruleset"
if [ -n "$type" ]; then
echo "$section-$name-$type-$postfix"
else
echo "$section-$name-$postfix"
fi
}
# Creates a new ruleset JSON file if it doesn't already exist
create_source_rule_set() {
local ruleset_filepath="$1"
if file_exists "$ruleset_filepath"; then
return 3
fi
jq -n '{version: 3, rules: []}' > "$ruleset_filepath"
}
#######################################
# Patch a source ruleset JSON file for sing-box by appending a new ruleset object containing the provided key
# and value.
# Arguments:
# filepath: path to the JSON file to patch
# key: the ruleset key to insert (e.g., "ip_cidr")
# value: a JSON array of values to assign to the key
# Example:
# patch_source_ruleset_rules "/tmp/sing-box/ruleset.json" "ip_cidr" '["1.1.1.1","2.2.2.2"]'
#######################################
patch_source_ruleset_rules() {
local filepath="$1"
local key="$2"
local value="$3"
local tmpfile=$(mktemp)
jq --arg key "$key" --argjson value "$value" \
'( .rules | map(has($key)) | index(true) ) as $idx |
if $idx != null then
.rules[$idx][$key] = (.rules[$idx][$key] + $value | unique)
else
.rules += [{ ($key): $value }]
end' "$filepath" > "$tmpfile"
if [ $? -ne 0 ]; then
rm -f "$tmpfile"
return 1
fi
mv "$tmpfile" "$filepath"
}
# Imports a plain domain list into a ruleset in chunks, validating domains and appending them as domain_suffix rules
import_plain_domain_list_to_local_source_ruleset_chunked() {
local plain_list_filepath="$1"
local ruleset_filepath="$2"
local chunk_size="${3:-5000}"
local array count json_array
count=0
while IFS= read -r line; do
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -z "$line" ] && continue
if ! is_domain_suffix "$line"; then
log "'$line' is not a valid domain" "debug"
continue
fi
if [ -z "$array" ]; then
array="$line"
else
array="$array,$line"
fi
count=$((count + 1))
if [ "$count" = "$chunk_size" ]; then
log "Adding $count elements to rule set at $ruleset_filepath" "debug"
json_array="$(comma_string_to_json_array "$array")"
patch_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array"
array=""
count=0
fi
done < "$plain_list_filepath"
if [ -n "$array" ]; then
log "Adding $count elements to rule set at $ruleset_filepath" "debug"
json_array="$(comma_string_to_json_array "$array")"
patch_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array"
fi
}
# Imports a plain IPv4/CIDR list into a ruleset in chunks, validating entries and appending them as ip_cidr rules
import_plain_subnet_list_to_local_source_ruleset_chunked() {
local plain_list_filepath="$1"
local ruleset_filepath="$2"
local chunk_size="${3:-5000}"
local array count json_array
count=0
while IFS= read -r line; do
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -z "$line" ] && continue
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
continue
fi
if [ -z "$array" ]; then
array="$line"
else
array="$array,$line"
fi
count=$((count + 1))
if [ "$count" = "$chunk_size" ]; then
log "Adding $count elements to ruleset at $ruleset_filepath" "debug"
json_array="$(comma_string_to_json_array "$array")"
patch_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
array=""
count=0
fi
done < "$plain_list_filepath"
if [ -n "$array" ]; then
log "Adding $count elements to ruleset at $ruleset_filepath" "debug"
json_array="$(comma_string_to_json_array "$array")"
patch_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
fi
}
# Determines the ruleset format based on the file extension (json → source, srs → binary)
get_ruleset_format_by_file_extension() {
local file_extension="$1"
local format
case "$file_extension" in
json) format="source" ;;
srs) format="binary" ;;
*)
log "Unsupported file extension: .$file_extension" "error"
return 1
;;
esac
echo "$format"
}
# Decompiles a sing-box SRS binary file into a JSON ruleset file
decompile_binary_ruleset() {
local binary_filepath="$1"
local output_filepath="$2"
log "Decompiling $binary_filepath to $output_filepath" "debug"
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
if [[ $? -ne 0 ]]; then
log "Decompilation command failed for $binary_filepath" "error"
return 1
fi
}
# Extracts all ip_cidr entries from a JSON ruleset file and writes them to an output file.
extract_ip_cidr_from_json_ruleset_to_file() {
local json_file="$1"
local output_file="$2"
log "Extracting ip_cidr entries from $json_file to $output_file" "debug"
jq -r '.rules[].ip_cidr[]' "$json_file" > "$output_file"
}

View File

@@ -64,7 +64,8 @@ sing_box_cf_add_proxy_outbound() {
url=$(url_decode "$url") url=$(url_decode "$url")
url=$(url_strip_fragment "$url") url=$(url_strip_fragment "$url")
local scheme="${url%%://*}" local scheme
scheme="$(url_get_scheme "$url")"
case "$scheme" in case "$scheme" in
socks4 | socks4a | socks5) socks4 | socks4a | socks5)
local tag host port version userinfo username password udp_over_tcp local tag host port version userinfo username password udp_over_tcp
@@ -146,6 +147,21 @@ sing_box_cf_add_proxy_outbound() {
config=$(_add_outbound_security "$config" "$tag" "$url") config=$(_add_outbound_security "$config" "$tag" "$url")
config=$(_add_outbound_transport "$config" "$tag" "$url") config=$(_add_outbound_transport "$config" "$tag" "$url")
;; ;;
hysteria2 | hy2)
local tag host port password obfuscator_type obfuscator_password upload_mbps download_mbps
tag=$(get_outbound_tag_by_section "$section")
host=$(url_get_host "$url")
port="$(url_get_port "$url")"
password=$(url_get_userinfo "$url")
obfuscator_type=$(url_get_query_param "$url" "obfs")
obfuscator_password=$(url_get_query_param "$url" "obfs-password")
upload_mbps=$(url_get_query_param "$url" "upmbps")
download_mbps=$(url_get_query_param "$url" "downmbps")
config=$(sing_box_cm_add_hysteria2_outbound "$config" "$tag" "$host" "$port" "$password" "$obfuscator_type" \
"$obfuscator_password" "$upload_mbps" "$download_mbps")
config=$(_add_outbound_security "$config" "$tag" "$url")
;;
*) *)
log "Unsupported proxy $scheme type. Aborted." "fatal" log "Unsupported proxy $scheme type. Aborted." "fatal"
exit 1 exit 1
@@ -160,13 +176,20 @@ _add_outbound_security() {
local outbound_tag="$2" local outbound_tag="$2"
local url="$3" local url="$3"
local security local security scheme
security=$(url_get_query_param "$url" "security") security=$(url_get_query_param "$url" "security")
if [ -z "$security" ]; then
scheme="$(url_get_scheme "$url")"
if [ "$scheme" = "hysteria2" ] || [ "$scheme" = "hy2" ]; then
security="tls"
fi
fi
case "$security" in case "$security" in
tls | reality) tls | reality)
local sni insecure alpn fingerprint public_key short_id local sni insecure alpn fingerprint public_key short_id
sni=$(url_get_query_param "$url" "sni") sni=$(url_get_query_param "$url" "sni")
insecure=$(url_get_query_param "$url" "allowInsecure") insecure=$(_get_insecure_query_param_from_url "$url")
alpn=$(comma_string_to_json_array "$(url_get_query_param "$url" "alpn")") alpn=$(comma_string_to_json_array "$(url_get_query_param "$url" "alpn")")
fingerprint=$(url_get_query_param "$url" "fp") fingerprint=$(url_get_query_param "$url" "fp")
public_key=$(url_get_query_param "$url" "pbk") public_key=$(url_get_query_param "$url" "pbk")
@@ -193,6 +216,18 @@ _add_outbound_security() {
echo "$config" echo "$config"
} }
_get_insecure_query_param_from_url() {
local url="$1"
local insecure
insecure=$(url_get_query_param "$url" "allowInsecure")
if [ -z "$insecure" ]; then
insecure=$(url_get_query_param "$url" "insecure")
fi
echo "$insecure"
}
_add_outbound_transport() { _add_outbound_transport() {
local config="$1" local config="$1"
local outbound_tag="$2" local outbound_tag="$2"
@@ -214,7 +249,12 @@ _add_outbound_transport() {
;; ;;
grpc) grpc)
# TODO(ampetelin): Add handling of optional gRPC parameters; example links are needed. # TODO(ampetelin): Add handling of optional gRPC parameters; example links are needed.
config=$(sing_box_cm_set_grpc_transport_for_outbound "$config" "$outbound_tag") local grpc_service_name
grpc_service_name=$(url_get_query_param "$url" "serviceName")
config=$(
sing_box_cm_set_grpc_transport_for_outbound "$config" "$outbound_tag" "$grpc_service_name"
)
;; ;;
*) *)
log "Unknown transport '$transport' detected." "error" log "Unknown transport '$transport' detected." "error"

View File

@@ -21,9 +21,9 @@ SERVICE_TAG="__service_tag"
####################################### #######################################
# Configure the logging section of a sing-box JSON configuration. # Configure the logging section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string, JSON configuration
# disabled: boolean, true to disable logging # disabled: boolean, true to disable logging
# level: string, e.g., "info", "debug", "warn" # level: string, log level. One of: trace debug info warn error fatal panic.
# timestamp: boolean, true to include timestamps # timestamp: boolean, true to include timestamps
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
@@ -50,7 +50,7 @@ sing_box_cm_configure_log() {
####################################### #######################################
# Configure the DNS section of a sing-box JSON configuration. # Configure the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# final: string, default dns server tag # final: string, default dns server tag
# strategy: string, default domain strategy for resolving the domain names # strategy: string, default domain strategy for resolving the domain names
# independent_cache: boolean, whether to use an independent DNS cache # independent_cache: boolean, whether to use an independent DNS cache
@@ -82,12 +82,12 @@ sing_box_cm_configure_dns() {
####################################### #######################################
# Add a UDP DNS server to the DNS section of a sing-box JSON configuration. # Add a UDP DNS server to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the DNS server # tag: string, identifier for the DNS server
# server_address: string, IP address or hostname of the DNS server # server_address: string, IP address or hostname of the DNS server
# server_port: string or number, port of the DNS server # server_port: string or integer, port of the DNS server
# domain_resolver: string, domain resolver to use for resolving domain names # domain_resolver: string, domain resolver to use for resolving domain names (optional)
# detour: string, tag of the upstream outbound # detour: string, tag of the upstream outbound (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -122,12 +122,12 @@ sing_box_cm_add_udp_dns_server() {
####################################### #######################################
# Add a TLS DNS server to the DNS section of a sing-box JSON configuration. # Add a TLS DNS server to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the DNS server # tag: string, identifier for the DNS server
# server_address: string, IP address or hostname of the DNS server # server_address: string, IP address or hostname of the DNS server
# server_port: string or number, port of the DNS server # server_port: string or integer, port of the DNS server
# domain_resolver: string, domain resolver to use for resolving domain names # domain_resolver: string, domain resolver to use for resolving domain names (optional)
# detour: string, tag of the upstream outbound # detour: string, tag of the upstream outbound (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -162,14 +162,14 @@ sing_box_cm_add_tls_dns_server() {
####################################### #######################################
# Add an HTTPS DNS server to the DNS section of a sing-box JSON configuration. # Add an HTTPS DNS server to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the DNS server # tag: string, identifier for the DNS server
# server_address: string, IP address or hostname of the DNS server # server_address: string, IP address or hostname of the DNS server
# server_port: string or number, port of the DNS server # server_port: string or integer, port of the DNS server
# path: string, optional URL path for HTTPS DNS requests # path: string, URL path for HTTPS DNS requests (optional)
# headers: string, optional additional headers for HTTPS DNS requests # headers: string, additional headers for HTTPS DNS requests (optional)
# domain_resolver: string, domain resolver to use for resolving domain names # domain_resolver: string, domain resolver to use for resolving domain names (optional)
# detour: string, tag of the upstream outbound # detour: string, tag of the upstream outbound (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -210,7 +210,7 @@ sing_box_cm_add_https_dns_server() {
####################################### #######################################
# Add a FakeIP DNS server to the DNS section of a sing-box JSON configuration. # Add a FakeIP DNS server to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the DNS server # tag: string, identifier for the DNS server
# inet4_range: string, IPv4 range used for fake IP mapping # inet4_range: string, IPv4 range used for fake IP mapping
# Outputs: # Outputs:
@@ -236,7 +236,7 @@ sing_box_cm_add_fakeip_dns_server() {
####################################### #######################################
# Add a DNS routing rule to the DNS section of a sing-box JSON configuration. # Add a DNS routing rule to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# server: string, target DNS server for the rule # server: string, target DNS server for the rule
# tag: string, identifier for the route rule # tag: string, identifier for the route rule
# Outputs: # Outputs:
@@ -263,10 +263,10 @@ sing_box_cm_add_dns_route_rule() {
####################################### #######################################
# Patch a DNS routing rule in the DNS section of a sing-box JSON configuration. # Patch a DNS routing rule in the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the rule to patch # tag: string, identifier of the rule to patch
# key: string, the key in the rule to update or add # key: string, the key in the rule to update or add
# value: JSON value to assign to the key # value: string, JSON value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -304,9 +304,9 @@ sing_box_cm_patch_dns_route_rule() {
####################################### #######################################
# Add a DNS reject rule to the DNS section of a sing-box JSON configuration. # Add a DNS reject rule to the DNS section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# key: string, the key to set for the reject rule # key: string, the key to set for the reject rule
# value: JSON value to assign to the key # value: string, JSON value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -331,10 +331,10 @@ sing_box_cm_add_dns_reject_rule() {
####################################### #######################################
# Add a TProxy inbound to the inbounds section of a sing-box JSON configuration. # Add a TProxy inbound to the inbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the inbound # tag: string, identifier for the inbound
# listen_address: string, IP address to listen on # listen_address: string, IP address to listen on
# listen_port: number, port to listen on # listen_port: integer, port to listen on
# tcp_fast_open: boolean, enable or disable TCP Fast Open # tcp_fast_open: boolean, enable or disable TCP Fast Open
# udp_fragment: boolean, enable or disable UDP fragmentation # udp_fragment: boolean, enable or disable UDP fragmentation
# Outputs: # Outputs:
@@ -369,10 +369,10 @@ sing_box_cm_add_tproxy_inbound() {
####################################### #######################################
# Add a Direct inbound to the inbounds section of a sing-box JSON configuration. # Add a Direct inbound to the inbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the inbound # tag: string, identifier for the inbound
# listen_address: string, IP address to listen on # listen_address: string, IP address to listen on
# listen_port: number, port to listen on # listen_port: integer, port to listen on
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -399,10 +399,10 @@ sing_box_cm_add_direct_inbound() {
####################################### #######################################
# Add a Mixed inbound to the inbounds section of a sing-box JSON configuration. # Add a Mixed inbound to the inbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the inbound # tag: string, identifier for the inbound
# listen_address: string, IP address to listen on # listen_address: string, IP address to listen on
# listen_port: number, port to listen on # listen_port: integer, port to listen on
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -429,7 +429,7 @@ sing_box_cm_add_mixed_inbound() {
####################################### #######################################
# Add a Direct outbound to the outbounds section of a sing-box JSON configuration. # Add a Direct outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
@@ -451,15 +451,15 @@ sing_box_cm_add_direct_outbound() {
####################################### #######################################
# Add a SOCKS outbound to the outbounds section of a sing-box JSON configuration. # Add a SOCKS outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# server_address: string, IP address or hostname of the SOCKS server # server_address: string, IP address or hostname of the SOCKS server
# server_port: number, port of the SOCKS server # server_port: integer, port of the SOCKS server
# version: string, optional SOCKS version # version: string, SOCKS version (optional)
# username: string, optional username for authentication # username: string, username for authentication (optional)
# password: string, optional password for authentication # password: string, password for authentication (optional)
# network: string, optional network type (e.g., "tcp") # network: string, network type (e.g., "tcp") (optional)
# udp_over_tcp: number, optional version for UDP over TCP # udp_over_tcp: integer, version for UDP over TCP (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -509,16 +509,16 @@ sing_box_cm_add_socks_outbound() {
####################################### #######################################
# Add a Shadowsocks outbound to the outbounds section of a sing-box JSON configuration. # Add a Shadowsocks outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# server_address: string, IP address or hostname of the Shadowsocks server # server_address: string, IP address or hostname of the Shadowsocks server
# server_port: number, port of the Shadowsocks server # server_port: integer, port of the Shadowsocks server
# method: string, encryption method # method: string, encryption method
# password: string, password for encryption # password: string, password for encryption
# network: string, optional network type (e.g., "tcp") # network: string, network type (e.g., "tcp") (optional)
# udp_over_tcp: number, optional version for UDP over TCP # udp_over_tcp: integer, version for UDP over TCP (optional)
# plugin: string, optional plugin name # plugin: string, plugin name (optional)
# plugin_opts: string, optional plugin options # plugin_opts: string, plugin options (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -573,14 +573,14 @@ sing_box_cm_add_shadowsocks_outbound() {
####################################### #######################################
# Add a VLESS outbound to the outbounds section of a sing-box JSON configuration. # Add a VLESS outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# server_address: string, IP address or hostname of the VLESS server # server_address: string, IP address or hostname of the VLESS server
# server_port: number, port of the VLESS server # server_port: integer, port of the VLESS server
# uuid: string, user UUID # uuid: string, user UUID
# flow: string, optional flow setting # flow: string, flow setting (optional)
# network: string, optional network type (e.g., "tcp") # network: string, network type (e.g., "tcp") (optional)
# packet_encoding: string, optional packet encoding method # packet_encoding: string, packet encoding method (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -624,12 +624,12 @@ sing_box_cm_add_vless_outbound() {
####################################### #######################################
# Add a Trojan outbound to the outbounds section of a sing-box JSON configuration. # Add a Trojan outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: string, JSON configuration # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# server_address: string, IP address or hostname of the Trojan server # server_address: string, IP address or hostname of the Trojan server
# server_port: number, port of the Trojan server # server_port: integer, port of the Trojan server
# password: string, password for authentication # password: string, password for authentication
# network: string, optional network type (e.g., "tcp") # network: string, network type (e.g., "tcp") (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -661,15 +661,76 @@ sing_box_cm_add_trojan_outbound() {
)]' )]'
} }
#######################################
# Add a Hysteria2 outbound to the outbounds section of a sing-box JSON configuration.
# Arguments:
# config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound
# server_address: string, IP address or hostname of the Hysteria2 server
# server_port: integer, port of the Hysteria2 server
# password: string, password for authentication
# obfuscator_type: string, obfuscation type (optional)
# obfuscator_password: string, obfuscation password (optional)
# upload_mbps: integer, upload bandwidth limit in Mbps (optional)
# download_mbps: integer, download bandwidth limit in Mbps (optional)
# network: string, network type (e.g., "udp") (optional)
# Outputs:
# Writes updated JSON configuration to stdout
# Example:
# CONFIG=$(sing_box_cm_add_hysteria2_outbound "$CONFIG" "hysteria2-out" "example.com" 443 "supersecret" \
# "salamander" "obfs-pass" "50" "200" "udp")
#######################################
sing_box_cm_add_hysteria2_outbound() {
local config="$1"
local tag="$2"
local server_address="$3"
local server_port="$4"
local password="$5"
local obfuscator_type="$6"
local obfuscator_password="$7"
local upload_mbps="$8"
local download_mbps="$9"
local network="${10}"
echo "$config" | jq \
--arg tag "$tag" \
--arg server_address "$server_address" \
--arg server_port "$server_port" \
--arg password "$password" \
--arg obfuscator_type "$obfuscator_type" \
--arg obfuscator_password "$obfuscator_password" \
--arg upload_mbps "$upload_mbps" \
--arg download_mbps "$download_mbps" \
--arg network "$network" \
'.outbounds += [(
{
type: "hysteria2",
tag: $tag,
server: $server_address,
server_port: ($server_port | tonumber),
password: $password
}
+ (if $obfuscator_type != "" and $obfuscator_password != "" then {
obfs: {
type: $obfuscator_type,
password: $obfuscator_password
}
} else {} end)
+ (if $upload_mbps != "" then {up_mbps: ($upload_mbps | tonumber)} else {} end)
+ (if $download_mbps != "" then {down_mbps: ($download_mbps | tonumber)} else {} end)
+ (if $network != "" then {network: $network} else {} end)
)]'
}
####################################### #######################################
# Set gRPC transport settings for an outbound in a sing-box JSON configuration. # Set gRPC transport settings for an outbound in a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the outbound to modify # tag: string, identifier of the outbound to modify
# service_name: string, optional gRPC service name # service_name: string, gRPC service name (optional)
# idle_timeout: string or number, optional idle timeout # idle_timeout: string or integer, idle timeout (optional)
# ping_timeout: string or number, optional ping timeout # ping_timeout: string or integer, ping timeout (optional)
# permit_without_stream: boolean, optional flag for permitting without stream # permit_without_stream: boolean, flag for permitting without stream (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -709,12 +770,12 @@ sing_box_cm_set_grpc_transport_for_outbound() {
####################################### #######################################
# Set WebSocket transport settings for an outbound in a sing-box JSON configuration. # Set WebSocket transport settings for an outbound in a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the outbound to modify # tag: string, identifier of the outbound to modify
# path: string, WebSocket path # path: string, WebSocket path
# host: string, optional Host header for WebSocket # host: string, Host header for WebSocket (optional)
# max_early_data: number, optional maximum early data # max_early_data: integer, maximum early data (optional)
# early_data_header_name: string, optional header name for early data # early_data_header_name: string, header name for early data (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -759,14 +820,14 @@ sing_box_cm_set_ws_transport_for_outbound() {
####################################### #######################################
# Set TLS settings for an outbound in a sing-box JSON configuration. # Set TLS settings for an outbound in a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the outbound to modify # tag: string, identifier of the outbound to modify
# server_name: string, optional, used to verify the hostname on the returned certificates # server_name: string, used to verify the hostname on the returned certificates (optional)
# insecure: boolean, accept any server certificate # insecure: boolean, accept any server certificate (optional)
# alpn: JSON value or null, optional supported application level protocols # alpn: string, JSON value, supported application level protocols (optional)
# utls_fingerprint: string, optional uTLS fingerprint # utls_fingerprint: string, uTLS fingerprint (optional)
# reality_public_key: string, optional Reality public key # reality_public_key: string, Reality public key (optional)
# reality_short_id: string, optional Reality short ID # reality_short_id: string, Reality short ID (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -825,7 +886,7 @@ sing_box_cm_set_tls_for_outbound() {
####################################### #######################################
# Add a Direct outbound with a specific network interface to a sing-box JSON configuration. # Add a Direct outbound with a specific network interface to a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# interface: string, network interface to bind the outbound # interface: string, network interface to bind the outbound
# domain_resolver: string, tag of the domain resolver to be used for this outbound (optional) # domain_resolver: string, tag of the domain resolver to be used for this outbound (optional)
@@ -857,9 +918,9 @@ sing_box_cm_add_interface_outbound() {
####################################### #######################################
# Add a raw outbound JSON object to the outbounds section of a sing-box configuration. # Add a raw outbound JSON object to the outbounds section of a sing-box configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the outbound # tag: string, identifier for the outbound
# raw_outbound: JSON object, the raw outbound configuration to add # raw_outbound: string, JSON object, the raw outbound configuration to add
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -881,14 +942,14 @@ sing_box_cm_add_raw_outbound() {
####################################### #######################################
# Add a URLTest outbound to the outbounds section of a sing-box JSON configuration. # Add a URLTest outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the URLTest outbound # tag: string, identifier for the URLTest outbound
# outbounds: JSON array of outbound tags to test # outbounds: string, JSON array of outbound tags to test
# url: URL to probe (optional) # url: string, URL to probe (optional)
# interval: test interval (e.g., "10s") (optional) # interval: string, test interval (e.g., "10s") (optional)
# tolerance: max latency difference tolerated (optional) # tolerance: string or integer, max latency difference tolerated (optional)
# idle_timeout: idle timeout duration (optional) # idle_timeout: string or integer, idle timeout duration (optional)
# interrupt_exist_connections: flag to interrupt existing connections ("true"/"false") (optional) # interrupt_exist_connections: boolean, flag to interrupt existing connections ("true"/"false") (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -929,11 +990,11 @@ sing_box_cm_add_urltest_outbound() {
####################################### #######################################
# Add a Selector outbound to the outbounds section of a sing-box JSON configuration. # Add a Selector outbound to the outbounds section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the Selector outbound # tag: string, identifier for the Selector outbound
# outbounds: JSON array of outbound tags to choose from # outbounds: string (JSON), array of outbound tags to choose from
# default: default outbound tag if none selected (optional) # default: string, default outbound tag if none selected
# interrupt_exist_connections: flag to interrupt existing connections ("true"/"false") (optional) # interrupt_exist_connections: boolean, flag to interrupt existing connections ("true"/"false") (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -965,11 +1026,11 @@ sing_box_cm_add_selector_outbound() {
####################################### #######################################
# Configure the route section of a sing-box JSON configuration. # Configure the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# final: string, final outbound tag for unmatched traffic # final: string, final outbound tag for unmatched traffic
# auto_detect_interface: boolean, enable or disable automatic interface detection # auto_detect_interface: boolean, enable or disable automatic interface detection
# default_domain_resolver: string, default DNS resolver for domain-based routing # default_domain_resolver: string, default DNS resolver for domain-based routing
# default_interface: string, default network interface to use when auto detection is disabled # default_interface: string, default network interface to use when auto detection is disabled (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1001,7 +1062,7 @@ sing_box_cm_configure_route() {
####################################### #######################################
# Add a routing rule to the route section of a sing-box JSON configuration. # Add a routing rule to the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the route rule # tag: string, identifier for the route rule
# inbound: string, inbound tag to match # inbound: string, inbound tag to match
# outbound: string, outbound tag to route matched traffic to # outbound: string, outbound tag to route matched traffic to
@@ -1032,10 +1093,10 @@ sing_box_cm_add_route_rule() {
####################################### #######################################
# Patch a routing rule in the route section of a sing-box JSON configuration. # Patch a routing rule in the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the route rule to patch # tag: string, identifier of the route rule to patch
# key: string, the key in the rule to update or add # key: string, the key in the rule to update or add
# value: JSON value to assign to the key # value: string (JSON), value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1071,9 +1132,9 @@ sing_box_cm_patch_route_rule() {
####################################### #######################################
# Add a reject rule to the route section of a sing-box JSON configuration. # Add a reject rule to the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# key: string, the key to set for the reject rule # key: string, the key to set for the reject rule
# value: JSON value to assign to the key # value: string (JSON), value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1098,9 +1159,9 @@ sing_box_cm_add_reject_route_rule() {
####################################### #######################################
# Add a hijack-dns rule to the route section of a sing-box JSON configuration. # Add a hijack-dns rule to the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# key: string, the key to set for the hijack-dns rule # key: string, the key to set for the hijack-dns rule
# value: JSON value to assign to the key # value: string (JSON), value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1125,7 +1186,7 @@ sing_box_cm_add_hijack_dns_route_rule() {
####################################### #######################################
# Add a route-options rule to the route section of a sing-box JSON configuration. # Add a route-options rule to the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the route-options rule # tag: string, identifier for the route-options rule
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
@@ -1148,9 +1209,9 @@ sing_box_cm_add_options_route_rule() {
####################################### #######################################
# Add a sniff rule to the route section of a sing-box JSON configuration. # Add a sniff rule to the route section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# key: string, the key to set for the sniff rule # key: string, the key to set for the sniff rule
# value: JSON value to assign to the key # value: string (JSON), value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1176,7 +1237,7 @@ sing_box_cm_sniff_route_rule() {
####################################### #######################################
# Add an inline ruleset to the route.rule_set section of a sing-box JSON configuration. # Add an inline ruleset to the route.rule_set section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the inline ruleset # tag: string, identifier for the inline ruleset
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
@@ -1198,10 +1259,10 @@ sing_box_cm_add_inline_ruleset() {
####################################### #######################################
# Add or update a rule in an inline ruleset within the route.rule_set section of a sing-box JSON configuration. # Add or update a rule in an inline ruleset within the route.rule_set section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier of the inline ruleset # tag: string, identifier of the inline ruleset
# key: string, the key in the ruleset to update or add # key: string, the key in the ruleset to update or add
# value: JSON value to assign to the key # value: string (JSON), value to assign to the key
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1238,7 +1299,7 @@ sing_box_cm_add_inline_ruleset_rule() {
####################################### #######################################
# Add a local ruleset to the route.rule_set section of a sing-box JSON configuration. # Add a local ruleset to the route.rule_set section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the local ruleset # tag: string, identifier for the local ruleset
# format: string, format of the local ruleset ("source" or "binary") # format: string, format of the local ruleset ("source" or "binary")
# path: string, file path to the local ruleset # path: string, file path to the local ruleset
@@ -1269,12 +1330,12 @@ sing_box_cm_add_local_ruleset() {
####################################### #######################################
# Add a remote ruleset to the route.rule_set section of a sing-box JSON configuration. # Add a remote ruleset to the route.rule_set section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# tag: string, identifier for the remote ruleset # tag: string, identifier for the remote ruleset
# format: string, format of the remote ruleset ("source" or "binary") # format: string, format of the remote ruleset ("source" or "binary")
# url: string, URL to download the ruleset from # url: string, URL to download the ruleset from
# download_detour: string, optional detour tag for downloading # download_detour: string, detour tag for downloading (optional)
# update_interval: string, optional update interval for the ruleset # update_interval: string, update interval for the ruleset (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1310,7 +1371,7 @@ sing_box_cm_add_remote_ruleset() {
####################################### #######################################
# Configure the experimental cache_file section of a sing-box JSON configuration. # Configure the experimental cache_file section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# enabled: boolean, enable or disable file caching # enabled: boolean, enable or disable file caching
# path: string, file path for cache storage # path: string, file path for cache storage
# store_fakeip: boolean, whether to store fake IPs in the cache # store_fakeip: boolean, whether to store fake IPs in the cache
@@ -1339,9 +1400,10 @@ sing_box_cm_configure_cache_file() {
####################################### #######################################
# Configure the experimental clash_api section of a sing-box JSON configuration. # Configure the experimental clash_api section of a sing-box JSON configuration.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# external_controller: API listening address; Clash API will be disabled if empty # external_controller: string, API listening address; Clash API will be disabled if empty
# external_ui: Optional path to static web resources to serve at http://{{external-controller}}/ui # external_ui: string, path to static web resources to serve at http://{{external-controller}}/ui (optional)
# secret: string, secret for the RESTful API Authenticate by specifying HTTP header (optional)
# Outputs: # Outputs:
# Writes updated JSON configuration to stdout # Writes updated JSON configuration to stdout
# Example: # Example:
@@ -1351,65 +1413,23 @@ sing_box_cm_configure_clash_api() {
local config="$1" local config="$1"
local external_controller="$2" local external_controller="$2"
local external_ui="$3" local external_ui="$3"
local secret="$4"
echo "$config" | jq \ echo "$config" | jq \
--arg external_controller "$external_controller" \ --arg external_controller "$external_controller" \
--arg external_ui "$external_ui" \ --arg external_ui "$external_ui" \
--arg secret "$secret" \
'.experimental.clash_api = { '.experimental.clash_api = {
external_controller: $external_controller, external_controller: $external_controller,
} }
+ (if $external_ui != "" then { external_ui: $external_ui } else {} end)' + (if $external_ui != "" then { external_ui: $external_ui } else {} end)
} + (if $secret != "" then { secret: $secret } else {} end)'
#######################################
# Create a local source ruleset JSON file for sing-box.
# Arguments:
# filepath: path to the JSON file to create
# Example:
# sing_box_cm_create_local_source_ruleset "/tmp/sing-box/ruleset.json"
#######################################
sing_box_cm_create_local_source_ruleset() {
local filepath="$1"
jq -n '{version: 3, rules: []}' > "$filepath"
}
#######################################
# Patch a local source ruleset JSON file for sing-box by adding unique! values to a given key.
# Arguments:
# filepath: path to the JSON file to patch
# key: the ruleset key to update (e.g., "ip_cidr")
# value: a JSON array of values to add to the key
# Example:
# sing_box_cm_patch_local_source_ruleset_rules "/tmp/sing-box/ruleset.json" "ip_cidr" '["1.1.1.1","2.2.2.2"]'
#######################################
sing_box_cm_patch_local_source_ruleset_rules() {
local filepath="$1"
local key="$2"
local value="$3"
value=$(_normalize_arg "$value")
local content
content="$(cat "$filepath")"
echo "$content" | jq \
--arg key "$key" \
--argjson value "$value" '
([.rules[]?[$key][]] | unique) as $existing
| ($value - $existing) as $value
| if ($value | length) > 0 then
.rules += [{($key): $value}]
else
.
end
' > "$filepath"
} }
####################################### #######################################
# Save a sing-box JSON configuration to a file, removing service-specific tags. # Save a sing-box JSON configuration to a file, removing service-specific tags.
# Arguments: # Arguments:
# config: JSON configuration (string) # config: string (JSON), sing-box configuration to modify
# file_path: string, path to save the configuration file # file_path: string, path to save the configuration file
# Outputs: # Outputs:
# Writes the cleaned JSON configuration to the specified file # Writes the cleaned JSON configuration to the specified file