Merge branch 'MHSanaei:main' into main

This commit is contained in:
Suiranoil 2024-10-17 20:15:18 +03:00 committed by GitHub
commit f5e229833a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 433 additions and 211 deletions

View file

@ -83,7 +83,7 @@ jobs:
cd x-ui/bin cd x-ui/bin
# Download dependencies # Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.9.30/" Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.10.16/"
if [ "${{ matrix.platform }}" == "amd64" ]; then if [ "${{ matrix.platform }}" == "amd64" ]; then
wget ${Xray_URL}Xray-linux-64.zip wget ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip unzip Xray-linux-64.zip

View file

@ -27,7 +27,7 @@ case $1 in
esac esac
mkdir -p build/bin mkdir -p build/bin
cd build/bin cd build/bin
wget "https://github.com/XTLS/Xray-core/releases/download/v24.9.30/Xray-linux-${ARCH}.zip" wget "https://github.com/XTLS/Xray-core/releases/download/v24.10.16/Xray-linux-${ARCH}.zip"
unzip "Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
mv xray "xray-linux-${FNAME}" mv xray "xray-linux-${FNAME}"

View file

@ -30,38 +30,62 @@
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
``` ```
## Instalar una Versión Personalizada ## Instalar una Versión Personalizada (no recomendamos)
Para instalar la versión deseada, agrega la versión al final del comando de instalación. Por ejemplo, ver `v2.4.3`: Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
``` ```
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.3 VERSION=v1.7.9 bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/refs/tags/$VERSION/install.sh") $VERSION
``` ```
## Certificado SSL ## Certificado SSL
<details> <details>
<summary>Haz clic para el Certificado SSL</summary> <summary>Haga clic para ver los detalles del certificado SSL</summary>
### Cloudflare ### ACME
El script de gestión tiene una aplicación de certificado SSL incorporada para Cloudflare. Para usar este script para colocar un certificado, necesitas lo siguiente: Para gestionar certificados SSL utilizando ACME:
- Correo electrónico registrado en Cloudflare 1. Asegúrate de que tu dominio esté correctamente resuelto al servidor.
- Clave Global de API de Cloudflare 2. Ejecuta el comando `x-ui` en la terminal y elige `Gestión de Certificados SSL`.
- El nombre de dominio se ha resuelto en el servidor actual a través de Cloudflare 3. Se te presentarán las siguientes opciones:
**1:** Ejecuta el comando`x-ui`en la terminal, luego elige `Certificado SSL de Cloudflare`.
- **Get SSL:** Obtener certificados SSL.
- **Revoke:** Revocar certificados SSL existentes.
- **Force Renew:** Forzar la renovación de certificados SSL.
- **Show Existing Domains:** Mostrar todos los certificados de dominio disponibles en el servidor.
- **Set Certificate Paths for the Panel:** Especificar el certificado para tu dominio que será utilizado por el panel.
### Certbot ### Certbot
```
Para instalar y usar Certbot:
```sh
apt-get install certbot -y apt-get install certbot -y
certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com
certbot renew --dry-run certbot renew --dry-run
``` ```
***Consejo:*** *Certbot también está integrado en el script de gestión. Puedes ejecutar el comando `x-ui` , luego elegir `Gestión de Certificados SSL`.* ### Cloudflare
El script de gestión incluye una aplicación de certificado SSL integrada para Cloudflare. Para usar este script para solicitar un certificado, necesitas lo siguiente:
- Correo electrónico registrado en Cloudflare
- Clave API Global de Cloudflare
- El nombre de dominio debe estar resuelto al servidor actual a través de Cloudflare
**Cómo obtener la Clave API Global de Cloudflare:**
1. Ejecuta el comando `x-ui` en la terminal y elige `Certificado SSL de Cloudflare`.
2. Visita el enlace: [Tokens de API de Cloudflare](https://dash.cloudflare.com/profile/api-tokens).
3. Haz clic en "Ver Clave API Global" (consulta la captura de pantalla a continuación):
![](media/APIKey1.PNG)
4. Es posible que necesites volver a autenticar tu cuenta. Después de eso, se mostrará la Clave API (consulta la captura de pantalla a continuación):
![](media/APIKey2.png)
Al utilizarlo, simplemente ingresa tu `nombre de dominio`, `correo electrónico` y `CLAVE API`. El diagrama es el siguiente:
![](media/DetailEnter.png)
</details> </details>

View file

@ -30,12 +30,12 @@
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
``` ```
## Install Custom Version ## Install Custom Version (we don't recommend)
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.4.4`: To install your desired version, use following installation command. e.g., ver `v1.7.9`:
``` ```
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.4 VERSION=v1.7.9 bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/refs/tags/$VERSION/install.sh") $VERSION
``` ```
## SSL Certificate ## SSL Certificate
@ -54,6 +54,8 @@ To manage SSL certificates using ACME:
- **Get SSL:** Obtain SSL certificates. - **Get SSL:** Obtain SSL certificates.
- **Revoke:** Revoke existing SSL certificates. - **Revoke:** Revoke existing SSL certificates.
- **Force Renew:** Force renewal of SSL certificates. - **Force Renew:** Force renewal of SSL certificates.
- **Show Existing Domains:** Display all domain certificates available on the server.
- **Set Certificate Paths for the Panel:** Specify the certificate for your domain to be used by the panel.
### Certbot ### Certbot

View file

@ -30,12 +30,12 @@
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
``` ```
## Установка определённой версии ## Установка определённой версии (мы не рекомендуем)
Чтобы установить нужную вам версию, добавьте номер версии в конец команды установки. Например, `v2.4.3`: Чтобы установить желаемую версию, используйте следующую команду установки. Например, ver `v1.7.9`:
``` ```
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.3 VERSION=v1.7.9 bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/refs/tags/$VERSION/install.sh") $VERSION
``` ```
## SSL Сертификат ## SSL Сертификат
@ -54,6 +54,8 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
- **Get SSL:** Получить SSL сертификаты. - **Get SSL:** Получить SSL сертификаты.
- **Revoke:** Отозвать существующие SSL сертификаты. - **Revoke:** Отозвать существующие SSL сертификаты.
- **Force Renew:** Принудительно перевыпустить SSL сертификаты. - **Force Renew:** Принудительно перевыпустить SSL сертификаты.
- **Show Existing Domains:** Отобразить все сертификаты доменов, доступные на сервере.
- **Set Certificate Paths for the Panel:** Укажите сертификат для вашего домена, который будет использоваться панелью.
### Certbot ### Certbot

View file

@ -30,12 +30,12 @@
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
``` ```
## 安装指定版本 ## 安装指定版本 (我们不建议)
要安装所需的版本,请将该版本添加到安装命令的末尾。 e.g., ver `v2.4.3`: 要安装您想要的版本请使用以下安装命令。例如ver `v1.7.9`:
``` ```
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.3 VERSION=v1.7.9 bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/refs/tags/$VERSION/install.sh") $VERSION
``` ```
### SSL证书 ### SSL证书
@ -51,9 +51,11 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
2. 在终端中运行 `x-ui` 命令,然后选择 `SSL证书管理` 2. 在终端中运行 `x-ui` 命令,然后选择 `SSL证书管理`
3. 您将看到以下选项: 3. 您将看到以下选项:
- **获取SSL证书:** 获取SSL证书。 - **Get SSL:** 获取SSL证书。
- **吊销:** 吊销现有的SSL证书。 - **Revoke:** 吊销现有的SSL证书。
- **强制更新:** 强制更新SSL证书。 - **Force Renew:** 强制更新SSL证书。
- **Show Existing Domains:** 显示服务器上所有可用的域证书。
- **Set Certificate Paths for the Panel:** 指定用于面板的域证书。
### Certbot ### Certbot

View file

@ -1 +1 @@
2.4.4 2.4.5

10
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/goccy/go-json v0.10.3 github.com/goccy/go-json v0.10.3
github.com/mymmrac/telego v0.31.3 github.com/mymmrac/telego v0.31.3
github.com/nicksnyder/go-i18n/v2 v2.4.0 github.com/nicksnyder/go-i18n/v2 v2.4.1
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml/v2 v2.2.3 github.com/pelletier/go-toml/v2 v2.2.3
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
@ -32,7 +32,7 @@ require (
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/ebitengine/purego v0.8.0 // indirect github.com/ebitengine/purego v0.8.0 // indirect
github.com/fasthttp/router v1.5.2 // indirect github.com/fasthttp/router v1.5.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gabriel-vasile/mimetype v1.4.6 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
@ -49,7 +49,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.10 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
@ -62,7 +62,7 @@ require (
github.com/pires/go-proxyproto v0.8.0 // indirect github.com/pires/go-proxyproto v0.8.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.47.0 // indirect github.com/quic-go/quic-go v0.48.0 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect github.com/refraction-networking/utls v1.6.7 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect
@ -94,7 +94,7 @@ require (
golang.org/x/tools v0.26.0 // indirect golang.org/x/tools v0.26.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/protobuf v1.35.1 // indirect google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect

24
go.sum
View file

@ -1,5 +1,5 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I= github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM= github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
@ -26,8 +26,8 @@ github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+Gv
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fasthttp/router v1.5.2 h1:ckJCCdV7hWkkrMeId3WfEhz+4Gyyf6QPwxi/RHIMZ6I= github.com/fasthttp/router v1.5.2 h1:ckJCCdV7hWkkrMeId3WfEhz+4Gyyf6QPwxi/RHIMZ6I=
github.com/fasthttp/router v1.5.2/go.mod h1:C8EY53ozOwpONyevc/V7Gr8pqnEjwnkFFqPo1alAGs0= github.com/fasthttp/router v1.5.2/go.mod h1:C8EY53ozOwpONyevc/V7Gr8pqnEjwnkFFqPo1alAGs0=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE= github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
@ -82,8 +82,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@ -109,8 +109,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mymmrac/telego v0.31.3 h1:yZlD+dm+1W6p3OmCG8K+MbS02Y6paUgwPnqfZN3RWQQ= github.com/mymmrac/telego v0.31.3 h1:yZlD+dm+1W6p3OmCG8K+MbS02Y6paUgwPnqfZN3RWQQ=
github.com/mymmrac/telego v0.31.3/go.mod h1:coOoqXVmjFnwBlzusjfEezbQ7RH9wQnDowJdMm+bnEo= github.com/mymmrac/telego v0.31.3/go.mod h1:coOoqXVmjFnwBlzusjfEezbQ7RH9wQnDowJdMm+bnEo=
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM= github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
@ -129,8 +129,8 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= github.com/quic-go/quic-go v0.48.0 h1:2TCyvBrMu1Z25rvIAlnp2dPT4lgh/uTqLqiXVpp5AeU=
github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= github.com/quic-go/quic-go v0.48.0/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
@ -225,8 +225,8 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=

View file

@ -137,46 +137,61 @@ gen_random_string() {
} }
config_after_install() { config_after_install() {
echo -e "${yellow}Install/update finished! For security, it's recommended to modify panel settings ${plain}"
local existing_username=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'username: .+' | awk '{print $2}')
local existing_password=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'password: .+' | awk '{print $2}')
local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
# Check if username and password exist
if [[ -n "$existing_username" && -n "$existing_password" ]]; then
# If webBasePath is missing, generate a new one
if [[ ${#existing_webBasePath} -lt 4 ]]; then
local config_webBasePath=$(gen_random_string 15)
echo -e "${yellow}WebBasePath is missing or too short. Generating a new one...${plain}"
/usr/local/x-ui/x-ui setting -webBasePath "${config_webBasePath}"
echo -e "${green}New WebBasePath: ${config_webBasePath}${plain}"
else
echo -e "${green}Username, Password, and WebBasePath are already set. Exiting...${plain}"
fi
/usr/local/x-ui/x-ui migrate
return 0
fi
read -p "Would you like to customize the Panel Port settings? (If not, random settings will be applied) [y/n]: " config_confirm read -p "Would you like to customize the Panel Port settings? (If not, random settings will be applied) [y/n]: " config_confirm
local config_webBasePath=$(gen_random_string 15) local config_webBasePath=$(gen_random_string 15)
local config_account=$(gen_random_string 10) local config_username=$(gen_random_string 10)
local config_password=$(gen_random_string 10) local config_password=$(gen_random_string 10)
if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
read -p "Please set up the panel port: " config_port read -p "Please set up the panel port: " config_port
echo -e "${yellow}Your Panel Port is: ${config_port}${plain}" echo -e "${yellow}Your Panel Port is: ${config_port}${plain}"
echo -e "${yellow}Your Username will be generated randomly: ${config_account}${plain}" echo -e "${yellow}Your Username will be generated randomly: ${config_username}${plain}"
echo -e "${yellow}Your Password will be generated randomly: ${config_password}${plain}" echo -e "${yellow}Your Password will be generated randomly: ${config_password}${plain}"
echo -e "${yellow}Your Web Base Path will be generated randomly: ${config_webBasePath}${plain}" echo -e "${yellow}Your Web Base Path will be generated randomly: ${config_webBasePath}${plain}"
echo -e "${yellow}Initializing, please wait...${plain}" echo -e "${yellow}Initializing, please wait...${plain}"
/usr/local/x-ui/x-ui setting -username "${config_account}" -password "${config_password}" -port "${config_port}" -webBasePath "${config_webBasePath}" /usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}" -port "${config_port}" -webBasePath "${config_webBasePath}"
echo -e "${green}Settings applied successfully!${plain}" echo -e "${green}Settings applied successfully!${plain}"
echo -e "###############################################" echo -e "###############################################"
echo -e "${green}Username: ${config_account}${plain}" echo -e "${green}Username: ${config_username}${plain}"
echo -e "${green}Password: ${config_password}${plain}" echo -e "${green}Password: ${config_password}${plain}"
echo -e "${green}Port: ${config_port}${plain}" echo -e "${green}Port: ${config_port}${plain}"
echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" echo -e "${green}WebBasePath: ${config_webBasePath}${plain}"
echo -e "###############################################" echo -e "###############################################"
else else
echo -e "${red}Cancel...${plain}" echo -e "${red}Cancel...${plain}"
if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then
local portTemp=$(shuf -i 1024-62000 -n 1) local portTemp=$(shuf -i 1024-62000 -n 1)
/usr/local/x-ui/x-ui setting -username "${config_account}" -password "${config_password}" -port "${portTemp}" -webBasePath "${config_webBasePath}" /usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}" -port "${portTemp}" -webBasePath "${config_webBasePath}"
echo -e "This is a fresh installation, generating random login info for security concerns:" echo -e "This is a fresh installation, generating random login info for security concerns:"
echo -e "###############################################" echo -e "###############################################"
echo -e "${green}Username: ${config_account}${plain}" echo -e "${green}Username: ${config_username}${plain}"
echo -e "${green}Password: ${config_password}${plain}" echo -e "${green}Password: ${config_password}${plain}"
echo -e "${green}Port: ${portTemp}${plain}" echo -e "${green}Port: ${portTemp}${plain}"
echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" echo -e "${green}WebBasePath: ${config_webBasePath}${plain}"
@ -185,14 +200,6 @@ config_after_install() {
else else
echo -e "${yellow}This is your upgrade, keeping old settings. If you forgot your login info, you can type 'x-ui settings' to check${plain}" echo -e "${yellow}This is your upgrade, keeping old settings. If you forgot your login info, you can type 'x-ui settings' to check${plain}"
local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
if [[ ${#existing_webBasePath} -lt 4 ]]; then
echo -e "${yellow}WebBasePath is empty, generating a random one...${plain}"
/usr/local/x-ui/x-ui setting -webBasePath "${config_webBasePath}"
echo -e "${green}New WebBasePath: ${config_webBasePath}${plain}"
fi
fi fi
fi fi

View file

@ -47,7 +47,9 @@
"tag": "direct", "tag": "direct",
"protocol": "freedom", "protocol": "freedom",
"settings": { "settings": {
"domainStrategy": "UseIP" "domainStrategy": "UseIP",
"redirect": "",
"noises": []
} }
}, },
{ {

View file

@ -4,18 +4,14 @@ import (
"fmt" "fmt"
) )
func FormatTraffic(trafficBytes int64) (size string) { func FormatTraffic(trafficBytes int64) string {
if trafficBytes < 1024 { units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
return fmt.Sprintf("%.2fB", float64(trafficBytes)/float64(1)) unitIndex := 0
} else if trafficBytes < (1024 * 1024) { size := float64(trafficBytes)
return fmt.Sprintf("%.2fKB", float64(trafficBytes)/float64(1024))
} else if trafficBytes < (1024 * 1024 * 1024) { for size >= 1024 && unitIndex < len(units)-1 {
return fmt.Sprintf("%.2fMB", float64(trafficBytes)/float64(1024*1024)) size /= 1024
} else if trafficBytes < (1024 * 1024 * 1024 * 1024) { unitIndex++
return fmt.Sprintf("%.2fGB", float64(trafficBytes)/float64(1024*1024*1024))
} else if trafficBytes < (1024 * 1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fTB", float64(trafficBytes)/float64(1024*1024*1024*1024))
} else {
return fmt.Sprintf("%.2fEB", float64(trafficBytes)/float64(1024*1024*1024*1024*1024))
} }
return fmt.Sprintf("%.2f%s", size, units[unitIndex])
} }

View file

@ -141,8 +141,8 @@ class DBInbound {
} }
} }
genInboundLinks(remarkModel) { genInboundLinks(remarkModel) {
const inbound = this.toInbound(); const inbound = this.toInbound();
return inbound.genInboundLinks(this.remark,remarkModel); return inbound.genInboundLinks(this.remark, remarkModel);
} }
} }

View file

@ -890,7 +890,11 @@ Outbound.FreedomSettings = class extends CommonClass {
}; };
Outbound.FreedomSettings.Fragment = class extends CommonClass { Outbound.FreedomSettings.Fragment = class extends CommonClass {
constructor(packets = '1-3', length = '', interval = '') { constructor(
packets = '1-3',
length = '',
interval = ''
) {
super(); super();
this.packets = packets; this.packets = packets;
this.length = length; this.length = length;
@ -1178,7 +1182,8 @@ Outbound.WireguardSettings = class extends CommonClass {
domainStrategy = '', domainStrategy = '',
reserved = '', reserved = '',
peers = [new Outbound.WireguardSettings.Peer()], peers = [new Outbound.WireguardSettings.Peer()],
kernelMode = false kernelMode = false,
kernelTun = false
) { ) {
super(); super();
this.mtu = mtu; this.mtu = mtu;
@ -1190,6 +1195,7 @@ Outbound.WireguardSettings = class extends CommonClass {
this.reserved = Array.isArray(reserved) ? reserved.join(',') : reserved; this.reserved = Array.isArray(reserved) ? reserved.join(',') : reserved;
this.peers = peers; this.peers = peers;
this.kernelMode = kernelMode; this.kernelMode = kernelMode;
this.kernelTun = kernelTun;
} }
addPeer() { addPeer() {
@ -1210,6 +1216,7 @@ Outbound.WireguardSettings = class extends CommonClass {
json.reserved, json.reserved,
json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)), json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)),
json.kernelMode, json.kernelMode,
json.kernelTun,
); );
} }
@ -1223,6 +1230,7 @@ Outbound.WireguardSettings = class extends CommonClass {
reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined, reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined,
peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers), peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers),
kernelMode: this.kernelMode, kernelMode: this.kernelMode,
kernelTun: this.kernelTun,
}; };
} }
}; };

View file

@ -16,6 +16,7 @@ class AllSetting {
this.tgBotEnable = false; this.tgBotEnable = false;
this.tgBotToken = ""; this.tgBotToken = "";
this.tgBotProxy = ""; this.tgBotProxy = "";
this.tgBotAPIServer = "";
this.tgBotChatId = ""; this.tgBotChatId = "";
this.tgRunTime = "@daily"; this.tgRunTime = "@daily";
this.tgBotBackup = false; this.tgBotBackup = false;

View file

@ -530,9 +530,9 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
noSSEHeader = false, noSSEHeader = false,
xPaddingBytes = "100-1000", xPaddingBytes = "100-1000",
xmux = { xmux = {
maxConcurrency: 0, maxConcurrency: "16-32",
maxConnections: 0, maxConnections: 0,
cMaxReuseTimes: 0, cMaxReuseTimes: "64-128",
cMaxLifetimeMs: 0 cMaxLifetimeMs: 0
} }
) { ) {
@ -920,7 +920,9 @@ class RealityStreamSettings extends XrayCommonClass {
json.settings.publicKey, json.settings.publicKey,
json.settings.fingerprint, json.settings.fingerprint,
json.settings.serverName, json.settings.serverName,
json.settings.spiderX);} json.settings.spiderX
);
}
return new RealityStreamSettings( return new RealityStreamSettings(
json.show, json.show,
json.xver, json.xver,
@ -2644,13 +2646,21 @@ Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass {
}; };
Inbound.WireguardSettings = class extends XrayCommonClass { Inbound.WireguardSettings = class extends XrayCommonClass {
constructor(protocol, mtu = 1420, secretKey = Wireguard.generateKeypair().privateKey, peers = [new Inbound.WireguardSettings.Peer()], kernelMode = false) { constructor(
protocol,
mtu = 1420,
secretKey = Wireguard.generateKeypair().privateKey,
peers = [new Inbound.WireguardSettings.Peer()],
kernelMode = false,
kernelTun = false,
) {
super(protocol); super(protocol);
this.mtu = mtu; this.mtu = mtu;
this.secretKey = secretKey; this.secretKey = secretKey;
this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : ''; this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
this.peers = peers; this.peers = peers;
this.kernelMode = kernelMode; this.kernelMode = kernelMode;
this.kernelTun = kernelTun;
} }
addPeer() { addPeer() {
@ -2668,6 +2678,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
json.secretKey, json.secretKey,
json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)), json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)),
json.kernelMode, json.kernelMode,
json.kernelTun,
); );
} }
@ -2677,6 +2688,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
secretKey: this.secretKey, secretKey: this.secretKey,
peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers), peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers),
kernelMode: this.kernelMode, kernelMode: this.kernelMode,
kernelTun: this.kernelTun,
}; };
} }
}; };

View file

@ -5,9 +5,9 @@ const ONE_TB = ONE_GB * 1024;
const ONE_PB = ONE_TB * 1024; const ONE_PB = ONE_TB * 1024;
function sizeFormat(size) { function sizeFormat(size) {
if (size < 0) { if (size <= 0) return "0 B";
return "0 B";
} else if (size < ONE_KB) { if (size < ONE_KB) {
return size.toFixed(0) + " B"; return size.toFixed(0) + " B";
} else if (size < ONE_MB) { } else if (size < ONE_MB) {
return (size / ONE_KB).toFixed(2) + " KB"; return (size / ONE_KB).toFixed(2) + " KB";
@ -59,7 +59,7 @@ function formatSecond(second) {
return (second / 3600).toFixed(0) + 'h'; return (second / 3600).toFixed(0) + 'h';
} else { } else {
day = Math.floor(second / 3600 / 24); day = Math.floor(second / 3600 / 24);
remain = ((second/3600) - (day*24)).toFixed(0); remain = ((second / 3600) - (day * 24)).toFixed(0);
return day + 'd' + (remain > 0 ? ' ' + remain + 'h' : ''); return day + 'd' + (remain > 0 ? ' ' + remain + 'h' : '');
} }
} }
@ -149,7 +149,7 @@ function userExpiryColor(threshold, client, isDark = false) {
return isDark ? '#2c3950' : '#bcbcbc'; return isDark ? '#2c3950' : '#bcbcbc';
} }
now = new Date().getTime(), now = new Date().getTime(),
expiry = client.expiryTime; expiry = client.expiryTime;
switch (true) { switch (true) {
case expiry === null: case expiry === null:
return "#7a316f"; // purple return "#7a316f"; // purple

View file

@ -30,6 +30,7 @@ type AllSetting struct {
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"`
TgBotToken string `json:"tgBotToken" form:"tgBotToken"` TgBotToken string `json:"tgBotToken" form:"tgBotToken"`
TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"` TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"`
TgBotAPIServer string `json:"tgBotAPIServer" form:"tgBotAPIServer"`
TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"`
TgRunTime string `json:"tgRunTime" form:"tgRunTime"` TgRunTime string `json:"tgRunTime" form:"tgRunTime"`
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"`

View file

@ -150,6 +150,9 @@
<a-form-item label='Kernel Mode'> <a-form-item label='Kernel Mode'>
<a-switch v-model="outbound.settings.kernelMode"></a-switch> <a-switch v-model="outbound.settings.kernelMode"></a-switch>
</a-form-item> </a-form-item>
<a-form-item label='Kernel Tun'>
<a-switch v-model="outbound.settings.kernelTun"></a-switch>
</a-form-item>
<a-form-item> <a-form-item>
<template slot="label"> <template slot="label">
<a-tooltip> <a-tooltip>

View file

@ -21,6 +21,9 @@
<a-form-item label='Kernel Mode'> <a-form-item label='Kernel Mode'>
<a-switch v-model="inbound.settings.kernelMode"></a-switch> <a-switch v-model="inbound.settings.kernelMode"></a-switch>
</a-form-item> </a-form-item>
<a-form-item label='Kernel Tun'>
<a-switch v-model="inbound.settings.kernelTun"></a-switch>
</a-form-item>
<a-form-item label="Peers"> <a-form-item label="Peers">
<a-button icon="plus" type="primary" size="small" @click="inbound.settings.addPeer()"></a-button> <a-button icon="plus" type="primary" size="small" @click="inbound.settings.addPeer()"></a-button>
</a-form-item> </a-form-item>

View file

@ -12,7 +12,7 @@
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option> <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label='Dest'> <a-form-item label='Dest (Target)'>
<a-input v-model.trim="inbound.stream.reality.dest"></a-input> <a-input v-model.trim="inbound.stream.reality.dest"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='SNI'> <a-form-item label='SNI'>

View file

@ -4,18 +4,21 @@
<a-input v-model.trim="inbound.stream.splithttp.host"></a-input> <a-input v-model.trim="inbound.stream.splithttp.host"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "path" }}'> <a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.splithttp.path"></a-input> <a-input v-model.trim="inbound.stream.splithttp.path"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.splithttp.addHeader('host', '')"></a-button> <a-button icon="plus" size="small" @click="inbound.stream.splithttp.addHeader('host', '')"></a-button>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.splithttp.headers"> <a-input-group compact v-for="(header, index) in inbound.stream.splithttp.headers">
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'> <a-input style="width: 50%" v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template> <template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
</a-input> </a-input>
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> <a-input style="width: 50%" v-model.trim="header.value"
<a-button slot="addonAfter" size="small" @click="inbound.stream.splithttp.removeHeader(index)">-</a-button> placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button slot="addonAfter" size="small"
@click="inbound.stream.splithttp.removeHeader(index)">-</a-button>
</a-input> </a-input>
</a-input-group> </a-input-group>
</a-form-item> </a-form-item>
@ -35,16 +38,16 @@
<a-switch v-model="inbound.stream.splithttp.noSSEHeader"></a-switch> <a-switch v-model="inbound.stream.splithttp.noSSEHeader"></a-switch>
</a-form-item> </a-form-item>
<a-form-item label="Max Concurrency" v-if="!inbound.stream.splithttp.xmux.maxConnections"> <a-form-item label="Max Concurrency" v-if="!inbound.stream.splithttp.xmux.maxConnections">
<a-input-number v-model="inbound.stream.splithttp.xmux.maxConcurrency"></a-input-number> <a-input v-model="inbound.stream.splithttp.xmux.maxConcurrency"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="Max Connections" v-if="!inbound.stream.splithttp.xmux.maxConcurrency"> <a-form-item label="Max Connections" v-if="!inbound.stream.splithttp.xmux.maxConcurrency">
<a-input-number v-model="inbound.stream.splithttp.xmux.maxConnections"></a-input-number> <a-input v-model="inbound.stream.splithttp.xmux.maxConnections"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="Max Reuse Times"> <a-form-item label="Max Reuse Times">
<a-input-number v-model="inbound.stream.splithttp.xmux.cMaxReuseTimes"></a-input-number> <a-input v-model="inbound.stream.splithttp.xmux.cMaxReuseTimes"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="Max Lifetime (ms)"> <a-form-item label="Max Lifetime (ms)">
<a-input-number v-model="inbound.stream.splithttp.xmux.cMaxLifetimeMs"></a-input-number> <a-input v-model="inbound.stream.splithttp.xmux.cMaxLifetimeMs"></a-input>
</a-form-item> </a-form-item>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -373,6 +373,10 @@
<td>Kernel Mode</td> <td>Kernel Mode</td>
<td>[[ inbound.settings.kernelMode ]]</td> <td>[[ inbound.settings.kernelMode ]]</td>
</tr> </tr>
<tr>
<td>Kernel Tun</td>
<td>[[ inbound.settings.kernelTun ]]</td>
</tr>
<template v-for="(peer, index) in inbound.settings.peers"> <template v-for="(peer, index) in inbound.settings.peers">
<tr> <tr>
<td colspan="2"> <td colspan="2">

View file

@ -291,6 +291,7 @@
<a-select-option value="20">20</a-select-option> <a-select-option value="20">20</a-select-option>
<a-select-option value="50">50</a-select-option> <a-select-option value="50">50</a-select-option>
<a-select-option value="100">100</a-select-option> <a-select-option value="100">100</a-select-option>
<a-select-option value="500">500</a-select-option>
</a-select> </a-select>
<a-select size="small" v-model="logModal.level" style="width:95px;" <a-select size="small" v-model="logModal.level" style="width:95px;"
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme"> @change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">

View file

@ -246,6 +246,7 @@
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyLogin" }}' desc='{{ i18n "pages.settings.tgNotifyLoginDesc" }}' v-model="allSetting.tgBotLoginNotify"></setting-list-item> <setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyLogin" }}' desc='{{ i18n "pages.settings.tgNotifyLoginDesc" }}' v-model="allSetting.tgBotLoginNotify"></setting-list-item>
<setting-list-item type="number" title='{{ i18n "pages.settings.tgNotifyCpu" }}' desc='{{ i18n "pages.settings.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item> <setting-list-item type="number" title='{{ i18n "pages.settings.tgNotifyCpu" }}' desc='{{ i18n "pages.settings.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramProxy"}}' desc='{{ i18n "pages.settings.telegramProxyDesc"}}' v-model="allSetting.tgBotProxy" placeholder="socks5://user:pass@host:port"></setting-list-item> <setting-list-item type="text" title='{{ i18n "pages.settings.telegramProxy"}}' desc='{{ i18n "pages.settings.telegramProxyDesc"}}' v-model="allSetting.tgBotProxy" placeholder="socks5://user:pass@host:port"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramAPIServer"}}' desc='{{ i18n "pages.settings.telegramAPIServerDesc"}}' v-model="allSetting.tgBotAPIServer" placeholder="https://api.example.com"></setting-list-item>
<a-list-item> <a-list-item>
<a-row style="padding: 20px"> <a-row style="padding: 20px">
<a-col :lg="24" :xl="12"> <a-col :lg="24" :xl="12">
@ -382,12 +383,12 @@
<a-collapse v-if="enableDirect" style="margin-top: 14px;"> <a-collapse v-if="enableDirect" style="margin-top: 14px;">
<a-collapse-panel header='{{ i18n "pages.xray.directips"}}'> <a-collapse-panel header='{{ i18n "pages.xray.directips"}}'>
<a-list-item style="padding: 10px 20px"> <a-list-item style="padding: 10px 20px">
<a-checkbox-group v-model="geoIP" :options="geoIPOptions"></a-checkbox-group> <a-checkbox-group v-model="directIPs" :options="IPsOptions"></a-checkbox-group>
</a-list-item> </a-list-item>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.xray.directdomains"}}'> <a-collapse-panel header='{{ i18n "pages.xray.directdomains"}}'>
<a-list-item style="padding: 10px 20px"> <a-list-item style="padding: 10px 20px">
<a-checkbox-group v-model="geoSite" :options="geoSiteOptions"></a-checkbox-group> <a-checkbox-group v-model="directDomains" :options="DomainsOptions"></a-checkbox-group>
</a-list-item> </a-list-item>
</a-collapse-panel> </a-collapse-panel>
</a-collapse> </a-collapse>
@ -475,7 +476,7 @@
] ]
}, },
], ],
geoIPOptions: [ IPsOptions: [
{ label: 'Private IP', value: 'private' }, { label: 'Private IP', value: 'private' },
{ label: '🇮🇷 Iran', value: 'ir' }, { label: '🇮🇷 Iran', value: 'ir' },
{ label: '🇨🇳 China', value: 'cn' }, { label: '🇨🇳 China', value: 'cn' },
@ -487,7 +488,7 @@
{ label: '🇹🇷 Türkiye', value: 'tr' }, { label: '🇹🇷 Türkiye', value: 'tr' },
{ label: '🇧🇷 Brazil', value: 'br' }, { label: '🇧🇷 Brazil', value: 'br' },
], ],
geoSiteOptions: [ DomainsOptions: [
{ label: '🇮🇷 Iran', value: 'ir' }, { label: '🇮🇷 Iran', value: 'ir' },
{ label: '🇨🇳 China', value: 'cn' }, { label: '🇨🇳 China', value: 'cn' },
{ label: '🇷🇺 Russia', value: 'ru' }, { label: '🇷🇺 Russia', value: 'ru' },
@ -745,7 +746,7 @@
this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : ""; this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : "";
} }
}, },
geoIP: { directIPs: {
get: function () { get: function () {
if (!this.enableDirect) return []; if (!this.enableDirect) return [];
const rules = JSON.parse(this.allSetting.subJsonRules); const rules = JSON.parse(this.allSetting.subJsonRules);
@ -771,7 +772,7 @@
this.allSetting.subJsonRules = JSON.stringify(rules); this.allSetting.subJsonRules = JSON.stringify(rules);
} }
}, },
geoSite: { directDomains: {
get: function () { get: function () {
if (!this.enableDirect) return []; if (!this.enableDirect) return [];
const rules = JSON.parse(this.allSetting.subJsonRules); const rules = JSON.parse(this.allSetting.subJsonRules);

View file

@ -147,7 +147,8 @@
publicKey: peer.public_key, publicKey: peer.public_key,
endpoint: peer.endpoint.host, endpoint: peer.endpoint.host,
}], }],
kernelMode: false kernelMode: false,
kernelTun: false,
} }
}); });
} }

View file

@ -270,7 +270,7 @@
v-model="blockedDomains" v-model="blockedDomains"
:dropdown-class-name="themeSwitcher.currentTheme"> :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" <a-select-option :value="p.value" :label="p.label"
v-for="p in settingsData.DomainsOptions"> [[ p.label ]] v-for="p in settingsData.BlockDomainsOptions"> [[ p.label ]]
</a-select-option> </a-select-option>
</a-select> </a-select>
</template> </template>
@ -316,7 +316,7 @@
v-model="directDomains" v-model="directDomains"
:dropdown-class-name="themeSwitcher.currentTheme"> :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" <a-select-option :value="p.value" :label="p.label"
v-for="p in settingsData.DirectDomainsOptions"> [[ p.label ]] v-for="p in settingsData.DomainsOptions"> [[ p.label ]]
</a-select-option> </a-select-option>
</a-select> </a-select>
</template> </template>
@ -898,7 +898,7 @@
bittorrent: ["bittorrent"], bittorrent: ["bittorrent"],
}, },
IPsOptions: [ IPsOptions: [
{ label: 'Private IP', value: 'geoip:private' }, { label: 'Private IPs', value: 'geoip:private' },
{ label: '🇮🇷 Iran', value: 'ext:geoip_IR.dat:ir' }, { label: '🇮🇷 Iran', value: 'ext:geoip_IR.dat:ir' },
{ label: '🇨🇳 China', value: 'geoip:cn' }, { label: '🇨🇳 China', value: 'geoip:cn' },
{ label: '🇷🇺 Russia', value: 'geoip:ru' }, { label: '🇷🇺 Russia', value: 'geoip:ru' },
@ -910,12 +910,6 @@
{ label: '🇧🇷 Brazil', value: 'geoip:br' }, { label: '🇧🇷 Brazil', value: 'geoip:br' },
], ],
DomainsOptions: [ DomainsOptions: [
{ label: 'Ads All', value: 'geosite:category-ads-all' },
{ label: 'Ads IR 🇮🇷', value: 'ext:geosite_IR.dat:category-ads-all' },
{ label: 'Ads VN 🇻🇳', value: 'ext:geosite_VN.dat:ads' },
{ label: 'Sec-IR malware', value: 'geosite_IR.dat:malware' },
{ label: 'Sec-IR phishing', value: 'geosite_IR.dat:phishing' },
{ label: 'Sec-IR cryptominers', value: 'geosite_IR.dat:cryptominers' },
{ label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' }, { label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' },
{ label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' }, { label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' },
{ label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' }, { label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' },
@ -926,7 +920,13 @@
{ label: '🇻🇳 Vietnam', value: 'ext:geosite_VN.dat:vn' }, { label: '🇻🇳 Vietnam', value: 'ext:geosite_VN.dat:vn' },
{ label: '🇻🇳 .vn', value: 'regexp:.*\\.vn$' }, { label: '🇻🇳 .vn', value: 'regexp:.*\\.vn$' },
], ],
DirectDomainsOptions: [ BlockDomainsOptions: [
{ label: 'Ads All', value: 'geosite:category-ads-all' },
{ label: 'Ads IR 🇮🇷', value: 'ext:geosite_IR.dat:category-ads-all' },
{ label: 'Ads VN 🇻🇳', value: 'ext:geosite_VN.dat:ads' },
{ label: 'Malware 🇮🇷', value: 'ext:geosite_IR.dat:malware' },
{ label: 'Phishing 🇮🇷', value: 'ext:geosite_IR.dat:phishing' },
{ label: 'Cryptominers 🇮🇷', value: 'ext:geosite_IR.dat:cryptominers' },
{ label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' }, { label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' },
{ label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' }, { label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' },
{ label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' }, { label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' },

View file

@ -30,7 +30,9 @@
"tag": "direct", "tag": "direct",
"protocol": "freedom", "protocol": "freedom",
"settings": { "settings": {
"domainStrategy": "UseIP" "domainStrategy": "UseIP",
"redirect": "",
"noises": []
} }
}, },
{ {

View file

@ -1574,7 +1574,7 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e
return false, err return false, err
} }
for _, client := range clients { for _, client := range clients {
if client.Email == clientEmail { if client.Email == clientEmail && client.Enable {
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
cipher := "" cipher := ""
if string(inbound.Protocol) == "shadowsocks" { if string(inbound.Protocol) == "shadowsocks" {

View file

@ -41,6 +41,7 @@ var defaultValueMap = map[string]string{
"tgBotEnable": "false", "tgBotEnable": "false",
"tgBotToken": "", "tgBotToken": "",
"tgBotProxy": "", "tgBotProxy": "",
"tgBotAPIServer": "",
"tgBotChatId": "", "tgBotChatId": "",
"tgRunTime": "@daily", "tgRunTime": "@daily",
"tgBotBackup": "false", "tgBotBackup": "false",
@ -262,6 +263,14 @@ func (s *SettingService) SetTgBotProxy(token string) error {
return s.setString("tgBotProxy", token) return s.setString("tgBotProxy", token)
} }
func (s *SettingService) GetTgBotAPIServer() (string, error) {
return s.getString("tgBotAPIServer")
}
func (s *SettingService) SetTgBotAPIServer(token string) error {
return s.setString("tgBotAPIServer", token)
}
func (s *SettingService) GetTgBotChatId() (string, error) { func (s *SettingService) GetTgBotChatId() (string, error) {
return s.getString("tgBotChatId") return s.getString("tgBotChatId")
} }

View file

@ -108,8 +108,14 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
logger.Warning("Failed to get Telegram bot proxy URL:", err) logger.Warning("Failed to get Telegram bot proxy URL:", err)
} }
// Get Telegram bot API server URL
tgBotAPIServer, err := t.settingService.GetTgBotAPIServer()
if err != nil {
logger.Warning("Failed to get Telegram bot API server URL:", err)
}
// Create new Telegram bot instance // Create new Telegram bot instance
bot, err = t.NewBot(tgBotToken, tgBotProxy) bot, err = t.NewBot(tgBotToken, tgBotProxy, tgBotAPIServer)
if err != nil { if err != nil {
logger.Error("Failed to initialize Telegram bot API:", err) logger.Error("Failed to initialize Telegram bot API:", err)
return err return err
@ -125,26 +131,40 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
return nil return nil
} }
func (t *Tgbot) NewBot(token string, proxyUrl string) (*telego.Bot, error) { func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) {
if proxyUrl == "" { if proxyUrl == "" && apiServerUrl == "" {
// No proxy URL provided, use default instance
return telego.NewBot(token) return telego.NewBot(token)
} }
if !strings.HasPrefix(proxyUrl, "socks5://") { if proxyUrl != "" {
logger.Warning("Invalid socks5 URL, starting with default") if !strings.HasPrefix(proxyUrl, "socks5://") {
logger.Warning("Invalid socks5 URL, using default")
return telego.NewBot(token)
}
_, err := url.Parse(proxyUrl)
if err != nil {
logger.Warningf("Can't parse proxy URL, using default instance for tgbot: %v", err)
return telego.NewBot(token)
}
return telego.NewBot(token, telego.WithFastHTTPClient(&fasthttp.Client{
Dial: fasthttpproxy.FasthttpSocksDialer(proxyUrl),
}))
}
if !strings.HasPrefix(apiServerUrl, "http") {
logger.Warning("Invalid http(s) URL, using default")
return telego.NewBot(token) return telego.NewBot(token)
} }
_, err := url.Parse(proxyUrl) _, err := url.Parse(apiServerUrl)
if err != nil { if err != nil {
logger.Warning("Can't parse proxy URL, using default instance for tgbot:", err) logger.Warningf("Can't parse API server URL, using default instance for tgbot: %v", err)
return telego.NewBot(token) return telego.NewBot(token)
} }
return telego.NewBot(token, telego.WithFastHTTPClient(&fasthttp.Client{ return telego.NewBot(token, telego.WithAPIServer(apiServerUrl))
Dial: fasthttpproxy.FasthttpSocksDialer(proxyUrl),
}))
} }
func (t *Tgbot) IsRunning() bool { func (t *Tgbot) IsRunning() bool {
@ -243,7 +263,12 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
command, _, commandArgs := tu.ParseCommand(message.Text) command, _, commandArgs := tu.ParseCommand(message.Text)
// Extract the command from the Message. // Helper function to handle unknown commands.
handleUnknownCommand := func() {
msg += t.I18nBot("tgbot.commands.unknown")
}
// Handle the command.
switch command { switch command {
case "help": case "help":
msg += t.I18nBot("tgbot.commands.help") msg += t.I18nBot("tgbot.commands.help")
@ -266,9 +291,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
if isAdmin { if isAdmin {
t.searchClient(chatId, commandArgs[0]) t.searchClient(chatId, commandArgs[0])
} else { } else {
// Convert message.From.ID to int64 t.getClientUsage(chatId, int64(message.From.ID), commandArgs[0])
fromID := int64(message.From.ID)
t.getClientUsage(chatId, fromID, commandArgs[0])
} }
} else { } else {
msg += t.I18nBot("tgbot.commands.usage") msg += t.I18nBot("tgbot.commands.usage")
@ -278,19 +301,46 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
if isAdmin && len(commandArgs) > 0 { if isAdmin && len(commandArgs) > 0 {
t.searchInbound(chatId, commandArgs[0]) t.searchInbound(chatId, commandArgs[0])
} else { } else {
msg += t.I18nBot("tgbot.commands.unknown") handleUnknownCommand()
}
case "restart":
onlyMessage = true
if isAdmin {
if len(commandArgs) == 0 {
msg += t.I18nBot("tgbot.commands.restartUsage")
} else if strings.ToLower(commandArgs[0]) == "force" {
if t.xrayService.IsXrayRunning() {
err := t.xrayService.RestartXray(true)
if err != nil {
msg += t.I18nBot("tgbot.commands.restartFailed", "Error=="+err.Error())
} else {
msg += t.I18nBot("tgbot.commands.restartSuccess")
}
} else {
msg += t.I18nBot("tgbot.commands.xrayNotRunning")
}
} else {
handleUnknownCommand()
msg += t.I18nBot("tgbot.commands.restartUsage")
}
} else {
handleUnknownCommand()
} }
default: default:
msg += t.I18nBot("tgbot.commands.unknown") handleUnknownCommand()
} }
if msg != "" { if msg != "" {
if onlyMessage { t.sendResponse(chatId, msg, onlyMessage, isAdmin)
t.SendMsgToTgbot(chatId, msg) }
return }
} else {
t.SendAnswer(chatId, msg, isAdmin) // Helper function to send the message based on onlyMessage flag.
} func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
if onlyMessage {
t.SendMsgToTgbot(chatId, msg)
} else {
t.SendAnswer(chatId, msg, isAdmin)
} }
} }
@ -872,6 +922,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.onlines")).WithCallbackData(t.encodeQuery("onlines")), tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.onlines")).WithCallbackData(t.encodeQuery("onlines")),
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.allClients")).WithCallbackData(t.encodeQuery("get_inbounds")), tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.allClients")).WithCallbackData(t.encodeQuery("get_inbounds")),
), ),
// TODOOOOOOOOOOOOOO: Add restart button here.
) )
numericKeyboardClient := tu.InlineKeyboard( numericKeyboardClient := tu.InlineKeyboard(
tu.InlineKeyboardRow( tu.InlineKeyboardRow(

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'." "telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'."
"telegramProxy" = "SOCKS Proxy" "telegramProxy" = "SOCKS Proxy"
"telegramProxyDesc" = "Enables SOCKS5 proxy for connecting to Telegram. (adjust settings as per guide)" "telegramProxyDesc" = "Enables SOCKS5 proxy for connecting to Telegram. (adjust settings as per guide)"
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "The Telegram API server to use. Leave blank to use the default server."
"telegramChatId" = "Admin Chat ID" "telegramChatId" = "Admin Chat ID"
"telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(get it here @userinfobot) or (use '/id' command in the bot)" "telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(get it here @userinfobot) or (use '/id' command in the bot)"
"telegramNotifyTime" = "Notification Time" "telegramNotifyTime" = "Notification Time"
@ -483,8 +485,12 @@
"status" = "✅ Bot is OK!" "status" = "✅ Bot is OK!"
"usage" = "❗ Please provide a text to search!" "usage" = "❗ Please provide a text to search!"
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>" "getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "To search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>" "helpAdminCommands" = "To restart Xray Core:\r\n<code>/restart force</code>\r\n\r\nTo search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
"helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>" "helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Operation successful!"
"restartFailed" = "❗ Error in operation.\r\n\r\n<code>Error: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core is not running."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%" "cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "Debe obtener el token del administrador de bots de Telegram @botfather." "telegramTokenDesc" = "Debe obtener el token del administrador de bots de Telegram @botfather."
"telegramProxy" = "Socks5 Proxy" "telegramProxy" = "Socks5 Proxy"
"telegramProxyDesc" = "Si necesita el proxy Socks5 para conectarse a Telegram. Ajuste su configuración según la guía." "telegramProxyDesc" = "Si necesita el proxy Socks5 para conectarse a Telegram. Ajuste su configuración según la guía."
"telegramAPIServer" = "API Server de Telegram"
"telegramAPIServerDesc" = "El servidor API de Telegram a utilizar. Déjelo en blanco para utilizar el servidor predeterminado."
"telegramChatId" = "IDs de Chat de Telegram para Administradores" "telegramChatId" = "IDs de Chat de Telegram para Administradores"
"telegramChatIdDesc" = "IDs de Chat múltiples separados por comas. Use @userinfobot o use el comando '/id' en el bot para obtener sus IDs de Chat." "telegramChatIdDesc" = "IDs de Chat múltiples separados por comas. Use @userinfobot o use el comando '/id' en el bot para obtener sus IDs de Chat."
"telegramNotifyTime" = "Hora de Notificación del Bot de Telegram" "telegramNotifyTime" = "Hora de Notificación del Bot de Telegram"
@ -483,8 +485,12 @@
"status" = "✅ ¡El bot está bien!" "status" = "✅ ¡El bot está bien!"
"usage" = "❗ ¡Por favor proporciona un texto para buscar!" "usage" = "❗ ¡Por favor proporciona un texto para buscar!"
"getID" = "🆔 Tu ID: <code>{{ .ID }}</code>" "getID" = "🆔 Tu ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Para buscar un correo electrónico de cliente:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Observación]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>" "helpAdminCommands" = "Para reiniciar Xray Core:\r\n<code>/restart force</code>\r\n\r\nPara buscar un correo electrónico de cliente:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Observación]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>"
"helpClientCommands" = "Para buscar estadísticas, utiliza el siguiente comando:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>" "helpClientCommands" = "Para buscar estadísticas, utiliza el siguiente comando:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ ¡Operación exitosa!"
"restartFailed" = "❗ Error en la operación.\r\n\r\n<code>Error: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core no está en ejecución."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%" "cpuThreshold" = "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "دریافت کنید @botfather توکن را می‌توانید از" "telegramTokenDesc" = "دریافت کنید @botfather توکن را می‌توانید از"
"telegramProxy" = "SOCKS پراکسی" "telegramProxy" = "SOCKS پراکسی"
"telegramProxyDesc" = "را برای اتصال به تلگرام فعال می کند SOCKS5 پراکسی" "telegramProxyDesc" = "را برای اتصال به تلگرام فعال می کند SOCKS5 پراکسی"
"telegramAPIServer" = "سرور API تلگرام"
"telegramAPIServerDesc" = "API سرور تلگرام برای اتصال را تغییر میدهد. برای استفاده از سرور پیش فرض خالی بگذارید"
"telegramChatId" = "آی‌دی چت مدیر" "telegramChatId" = "آی‌دی چت مدیر"
"telegramChatIdDesc" = "دریافت ‌کنید ('/id'یا (دستور (@userinfobot) آی‌دی(های) چت تلگرام مدیر، از" "telegramChatIdDesc" = "دریافت ‌کنید ('/id'یا (دستور (@userinfobot) آی‌دی(های) چت تلگرام مدیر، از"
"telegramNotifyTime" = "زمان نوتیفیکیشن" "telegramNotifyTime" = "زمان نوتیفیکیشن"
@ -483,8 +485,12 @@
"status" = "✅ ربات در حالت عادی است!" "status" = "✅ ربات در حالت عادی است!"
"usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!" "usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!"
"getID" = "🆔 شناسه شما: <code>{{ .ID }}</code>" "getID" = "🆔 شناسه شما: <code>{{ .ID }}</code>"
"helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n\r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n<code>/inbound [توضیحات]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>" "helpAdminCommands" = "برای راه‌اندازی مجدد Xray Core:\r\n<code>/restart force</code>\r\n\r\nبرای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n\r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n<code>/inbound [توضیحات]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>"
"helpClientCommands" = "برای جستجوی آمار، از دستور زیر استفاده کنید:\r\n<code>/usage [ایمیل]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>" "helpClientCommands" = "برای جستجوی آمار، از دستور زیر استفاده کنید:\r\n<code>/usage [ایمیل]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ عملیات با موفقیت انجام شد!"
"restartFailed" = "❗ خطا در عملیات.\r\n\r\n<code>خطا: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core در حال اجرا نیست."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 بار ‌پردازنده {{ .Percent }}% بیشتر از آستانه است {{ .Threshold }}%" "cpuThreshold" = "🔴 بار ‌پردازنده {{ .Percent }}% بیشتر از آستانه است {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "Token bot Telegram yang diperoleh dari '@BotFather'." "telegramTokenDesc" = "Token bot Telegram yang diperoleh dari '@BotFather'."
"telegramProxy" = "Proxy SOCKS" "telegramProxy" = "Proxy SOCKS"
"telegramProxyDesc" = "Mengaktifkan proxy SOCKS5 untuk terhubung ke Telegram. (sesuaikan pengaturan sesuai panduan)" "telegramProxyDesc" = "Mengaktifkan proxy SOCKS5 untuk terhubung ke Telegram. (sesuaikan pengaturan sesuai panduan)"
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "Server API Telegram yang akan digunakan. Biarkan kosong untuk menggunakan server default."
"telegramChatId" = "ID Obrolan Admin" "telegramChatId" = "ID Obrolan Admin"
"telegramChatIdDesc" = "ID Obrolan Admin Telegram. (dipisahkan koma)(dapatkan di sini @userinfobot) atau (gunakan perintah '/id' di bot)" "telegramChatIdDesc" = "ID Obrolan Admin Telegram. (dipisahkan koma)(dapatkan di sini @userinfobot) atau (gunakan perintah '/id' di bot)"
"telegramNotifyTime" = "Waktu Notifikasi" "telegramNotifyTime" = "Waktu Notifikasi"
@ -482,9 +484,13 @@
"welcome" = "🤖 Selamat datang di <b>{{.Hostname }}</b> bot managemen.\r\n" "welcome" = "🤖 Selamat datang di <b>{{.Hostname }}</b> bot managemen.\r\n"
"status" = "✅ Bot dalam keadaan baik!" "status" = "✅ Bot dalam keadaan baik!"
"usage" = "❗ Harap berikan teks untuk mencari!" "usage" = "❗ Harap berikan teks untuk mencari!"
"getID" = "🆔 ID Anda:<code>{{.ID }}</code>" "getID" = "🆔 ID Anda: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Untuk mencari email klien:\r\n<code>/usage [Email]</code>\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n<code>/inbound [Catatan]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>" "helpAdminCommands" = "Untuk memulai ulang Xray Core:\r\n<code>/restart force</code>\r\n\r\nUntuk mencari email klien:\r\n<code>/usage [Email]</code>\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n<code>/inbound [Catatan]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>"
"helpClientCommands" = "Untuk mencari statistik, gunakan perintah berikut:\r\n<code>/usage [Email]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>" "helpClientCommands" = "Untuk mencari statistik, gunakan perintah berikut:\r\n<code>/usage [Email]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Operasi berhasil!"
"restartFailed" = "❗ Kesalahan dalam operasi.\r\n\r\n<code>Error: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core tidak berjalan."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 Beban CPU {{ .Percent }}% melebihi batas {{ .Threshold }}%" "cpuThreshold" = "🔴 Beban CPU {{ .Percent }}% melebihi batas {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "O token do bot do Telegram obtido de '@BotFather'." "telegramTokenDesc" = "O token do bot do Telegram obtido de '@BotFather'."
"telegramProxy" = "Proxy SOCKS" "telegramProxy" = "Proxy SOCKS"
"telegramProxyDesc" = "Ativa o proxy SOCKS5 para conectar ao Telegram. (ajuste as configurações conforme o guia)" "telegramProxyDesc" = "Ativa o proxy SOCKS5 para conectar ao Telegram. (ajuste as configurações conforme o guia)"
"telegramAPIServer" = "API Server do Telegram"
"telegramAPIServerDesc" = "O servidor API do Telegram a ser usado. Deixe em branco para usar o servidor padrão."
"telegramChatId" = "ID de Chat do Administrador" "telegramChatId" = "ID de Chat do Administrador"
"telegramChatIdDesc" = "O(s) ID(s) de Chat do Administrador no Telegram. (separado por vírgulas)(obtenha aqui @userinfobot) ou (use o comando '/id' no bot)" "telegramChatIdDesc" = "O(s) ID(s) de Chat do Administrador no Telegram. (separado por vírgulas)(obtenha aqui @userinfobot) ou (use o comando '/id' no bot)"
"telegramNotifyTime" = "Hora da Notificação" "telegramNotifyTime" = "Hora da Notificação"
@ -483,8 +485,12 @@
"status" = "✅ Bot está OK!" "status" = "✅ Bot está OK!"
"usage" = "❗ Por favor, forneça um texto para pesquisar!" "usage" = "❗ Por favor, forneça um texto para pesquisar!"
"getID" = "🆔 Seu ID: <code>{{ .ID }}</code>" "getID" = "🆔 Seu ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Para pesquisar por um email de cliente:\r\n<code>/usage [Email]</code>\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>" "helpAdminCommands" = "Para reiniciar o Xray Core:\r\n<code>/restart force</code>\r\n\r\nPara pesquisar por um email de cliente:\r\n<code>/usage [Email]</code>\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
"helpClientCommands" = "Para pesquisar por estatísticas, use o seguinte comando:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>" "helpClientCommands" = "Para pesquisar por estatísticas, use o seguinte comando:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Operação bem-sucedida!"
"restartFailed" = "❗ Erro na operação.\r\n\r\n<code>Erro: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core não está em execução."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 A carga da CPU {{ .Percent }}% excede o limite de {{ .Threshold }}%" "cpuThreshold" = "🔴 A carga da CPU {{ .Percent }}% excede o limite de {{ .Threshold }}%"

View file

@ -1,6 +1,6 @@
"username" = "Имя пользователя" "username" = "Имя пользователя"
"password" = "Пароль" "password" = "Пароль"
"login" = "Логин" "login" = "Войти"
"confirm" = "Подтвердить" "confirm" = "Подтвердить"
"cancel" = "Отмена" "cancel" = "Отмена"
"close" = "Закрыть" "close" = "Закрыть"
@ -67,12 +67,12 @@
"settings" = "Настройки панели" "settings" = "Настройки панели"
"xray" = "Настройки Xray" "xray" = "Настройки Xray"
"logout" = "Выход" "logout" = "Выход"
"link" = "Менеджмент" "link" = "Управление"
[pages.login] [pages.login]
"hello" = "Привет" "hello" = "Привет"
"title" = "Добро пожаловать" "title" = "Добро пожаловать"
"loginAgain" = "Время пребывания в сети вышло. Пожалуйста, войдите в систему снова" "loginAgain" = "Ваша сессия истекла. Пожалуйста, войдите в систему снова"
[pages.login.toasts] [pages.login.toasts]
"invalidFormData" = "Недопустимый формат данных" "invalidFormData" = "Недопустимый формат данных"
@ -93,8 +93,8 @@
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями" "xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
"operationHours" = "Время работы системы" "operationHours" = "Время работы системы"
"systemLoad" = "Системная нагрузка" "systemLoad" = "Системная нагрузка"
"systemLoadDesc" = "средняя загрузка системы за последние 1, 5 и 15 минут" "systemLoadDesc" = "Средняя загрузка системы за последние 1, 5 и 15 минут"
"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам." "connectionTcpCountDesc" = "Общее количество подключений TCP по всем сетевым картам."
"connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам." "connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам."
"connectionCount" = "Количество соединений" "connectionCount" = "Количество соединений"
"upSpeed" = "Общая скорость upload для всех сетей" "upSpeed" = "Общая скорость upload для всех сетей"
@ -133,21 +133,21 @@
"update" = "Обновить" "update" = "Обновить"
"modifyInbound" = "Изменить подключение" "modifyInbound" = "Изменить подключение"
"deleteInbound" = "Удалить подключение" "deleteInbound" = "Удалить подключение"
"deleteInboundContent" = "Подтвердите удаление подключения?" "deleteInboundContent" = "Вы уверены, что хотите удалить подключение?"
"deleteClient" = "Удалить клиента" "deleteClient" = "Удалить клиента"
"deleteClientContent" = "Вы уверены, что хотите удалить клиента?" "deleteClientContent" = "Вы уверены, что хотите удалить клиента?"
"resetTrafficContent" = "Подтвердите сброс трафика?" "resetTrafficContent" = "Вы уверены, что хотите сбросить трафик?"
"copyLink" = "Копировать ключ" "copyLink" = "Копировать ключ"
"address" = "Адрес" "address" = "Адрес"
"network" = "Сеть" "network" = "Сеть"
"destinationPort" = "Порт назначения" "destinationPort" = "Порт назначения"
"targetAddress" = "Целевой адрес" "targetAddress" = "Целевой адрес"
"monitorDesc" = "Оставьте пустым по умолчанию" "monitorDesc" = "Оставьте пустым для прослушивания всех IP-адресов"
"meansNoLimit" = "= Без ограничений (значение: ГБ)" "meansNoLimit" = "= Без ограничений (значение: ГБ)"
"totalFlow" = "Общий расход" "totalFlow" = "Общий расход"
"leaveBlankToNeverExpire" = "Оставьте пустым, чтобы не истекало" "leaveBlankToNeverExpire" = "Оставьте пустым, чтобы не истекало"
"noRecommendKeepDefault" = "Нет требований для сохранения настроек по умолчанию" "noRecommendKeepDefault" = "Рекомендуется оставить настройки по умолчанию"
"certificatePath" = "Путь файла" "certificatePath" = "Путь к файлу"
"certificateContent" = "Содержимое файла" "certificateContent" = "Содержимое файла"
"publicKey" = "Публичный ключ" "publicKey" = "Публичный ключ"
"privatekey" = "Приватный ключ" "privatekey" = "Приватный ключ"
@ -160,16 +160,16 @@
"cloneInboundOk" = "Клонировано" "cloneInboundOk" = "Клонировано"
"resetAllTraffic" = "Сбросить трафик всех подключений" "resetAllTraffic" = "Сбросить трафик всех подключений"
"resetAllTrafficTitle" = "Сброс трафика всех подключений" "resetAllTrafficTitle" = "Сброс трафика всех подключений"
"resetAllTrafficContent" = "Подтверждаете сброс трафика всех подключений?" "resetAllTrafficContent" = "Вы уверены, что хотите сбросить трафик всех подключений?"
"resetInboundClientTraffics" = "Сбросить трафик пользователей" "resetInboundClientTraffics" = "Сбросить трафик пользователей"
"resetInboundClientTrafficTitle" = "Сброс трафика пользователей" "resetInboundClientTrafficTitle" = "Сброс трафика пользователей"
"resetInboundClientTrafficContent" = "Вы уверены, что хотите сбросить весь трафик для этих пользователей?" "resetInboundClientTrafficContent" = "Вы уверены, что хотите сбросить весь трафик для этих пользователей?"
"resetAllClientTraffics" = "Сбросить трафик всех пользователей" "resetAllClientTraffics" = "Сбросить трафик всех пользователей"
"resetAllClientTrafficTitle" = "Сброс трафика всех пользователей" "resetAllClientTrafficTitle" = "Сброс трафика всех пользователей"
"resetAllClientTrafficContent" = "Подтверждаете сброс трафика всех пользователей?" "resetAllClientTrafficContent" = "Вы уверены, что хотите сбросить трафик всех пользователей?"
"delDepletedClients" = "Удалить отключенных пользователей" "delDepletedClients" = "Удалить отключенных пользователей"
"delDepletedClientsTitle" = "Удаление отключенных пользователей" "delDepletedClientsTitle" = "Удаление отключенных пользователей"
"delDepletedClientsContent" = "Подтверждаете удаление отключенных пользователей?" "delDepletedClientsContent" = "Вы уверены, что хотите удалить всех отключенных пользователей?"
"email" = "Email" "email" = "Email"
"emailDesc" = "Пожалуйста, укажите уникальный Email" "emailDesc" = "Пожалуйста, укажите уникальный Email"
"IPLimit" = "Ограничение по IP" "IPLimit" = "Ограничение по IP"
@ -220,7 +220,7 @@
"version" = "Версия" "version" = "Версия"
"method" = "Метод" "method" = "Метод"
"path" = "Путь" "path" = "Путь"
"status" = "Положение дел" "status" = "Статус"
"statusDescription" = "Описание статуса" "statusDescription" = "Описание статуса"
"requestHeader" = "Заголовок запроса" "requestHeader" = "Заголовок запроса"
"responseHeader" = "Заголовок ответа" "responseHeader" = "Заголовок ответа"
@ -228,9 +228,9 @@
[pages.settings] [pages.settings]
"title" = "Настройки" "title" = "Настройки"
"save" = "Сохранить" "save" = "Сохранить"
"infoDesc" = "Каждое сделанное здесь изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу" "infoDesc" = "Каждое выполненное изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу"
"restartPanel" = "Перезапуск панели" "restartPanel" = "Перезапуск панели"
"restartPanelDesc" = "Подтвердите перезапуск панели? ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере" "restartPanelDesc" = "Вы уверены, что хотите перезапустить панель?Нажмите ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере"
"actions" = "Действия" "actions" = "Действия"
"resetDefaultConfig" = "Сбросить на конфигурацию по умолчанию" "resetDefaultConfig" = "Сбросить на конфигурацию по умолчанию"
"panelSettings" = "Настройки панели" "panelSettings" = "Настройки панели"
@ -243,21 +243,21 @@
"panelPort" = "Порт панели" "panelPort" = "Порт панели"
"panelPortDesc" = "Порт, используемый для отображения этой панели" "panelPortDesc" = "Порт, используемый для отображения этой панели"
"publicKeyPath" = "Путь к файлу публичного ключа сертификата панели" "publicKeyPath" = "Путь к файлу публичного ключа сертификата панели"
"publicKeyPathDesc" = "Введите полный путь, начинающийся с" "publicKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
"privateKeyPath" = "Путь к файлу приватного ключа сертификата панели" "privateKeyPath" = "Путь к файлу приватного ключа сертификата панели"
"privateKeyPathDesc" = "Введите полный путь, начинающийся с" "privateKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
"panelUrlPath" = "Корневой путь URL адреса панели" "panelUrlPath" = "Корневой путь URL адреса панели"
"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на" "panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'"
"pageSize" = "Размер нумерации страниц" "pageSize" = "Размер нумерации страниц"
"pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить" "pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить"
"remarkModel" = "Модель примечания и символ разделения" "remarkModel" = "Модель примечания и символ разделения"
"datepicker" = "Выбор даты" "datepicker" = "Выбор даты"
"datepickerPlaceholder" = "Выберите дату" "datepickerPlaceholder" = "Выберите дату"
"datepickerDescription" = "Тип календаря выбора указывает дату истечения срока действия." "datepickerDescription" = "Запланированные задачи выполняются в соответствии с данным календарём"
"sampleRemark" = "Пример замечания" "sampleRemark" = "Пример замечания"
"oldUsername" = "Текущее имя пользователя" "oldUsername" = "Текущий логин"
"currentPassword" = "Текущий пароль" "currentPassword" = "Текущий пароль"
"newUsername" = "Новое имя пользователя" "newUsername" = "Новый логин"
"newPassword" = "Новый пароль" "newPassword" = "Новый пароль"
"telegramBotEnable" = "Включить Telegram бота" "telegramBotEnable" = "Включить Telegram бота"
"telegramBotEnableDesc" = "Подключайтесь к функциям этой панели через Telegram бота" "telegramBotEnableDesc" = "Подключайтесь к функциям этой панели через Telegram бота"
@ -265,8 +265,10 @@
"telegramTokenDesc" = "Необходимо получить токен у менеджера ботов Telegram @botfather" "telegramTokenDesc" = "Необходимо получить токен у менеджера ботов Telegram @botfather"
"telegramProxy" = "Прокси Socks5" "telegramProxy" = "Прокси Socks5"
"telegramProxyDesc" = "Если для подключения к Telegram вам нужен прокси Socks5. Настройте его параметры согласно руководству." "telegramProxyDesc" = "Если для подключения к Telegram вам нужен прокси Socks5. Настройте его параметры согласно руководству."
"telegramChatId" = "Telegram ChatID админа бота" "telegramAPIServer" = "API-сервер Telegram"
"telegramChatIdDesc" = "Множественные идентификаторы чата, разделенные запятыми. Чтобы получить свои идентификаторы чатов, используйте @userinfobot или команду '/id' в боте." "telegramAPIServerDesc" = "Используемый API-сервер Telegram. Оставьте пустым, чтобы использовать сервер по умолчанию."
"telegramChatId" = "Идентификатор Telegram администратора бота"
"telegramChatIdDesc" = "Один или несколько идентификаторов администратора бота. Чтобы получить идентификатор, используйте @userinfobot или команду '/id' в боте."
"telegramNotifyTime" = "Частота уведомлений бота Telegram" "telegramNotifyTime" = "Частота уведомлений бота Telegram"
"telegramNotifyTimeDesc" = "Используйте формат времени Crontab" "telegramNotifyTimeDesc" = "Используйте формат времени Crontab"
"tgNotifyBackup" = "Резервное копирование базы данных" "tgNotifyBackup" = "Резервное копирование базы данных"
@ -291,19 +293,19 @@
"subPort" = "Порт подписки" "subPort" = "Порт подписки"
"subPortDesc" = "Номер порта для обслуживания службы подписки не должен использоваться на сервере" "subPortDesc" = "Номер порта для обслуживания службы подписки не должен использоваться на сервере"
"subCertPath" = "Путь к файлу открытого ключа сертификата подписки" "subCertPath" = "Путь к файлу открытого ключа сертификата подписки"
"subCertPathDesc" = "Введите абсолютный путь, начинающийся с '/'" "subCertPathDesc" = "Введите полный путь, начинающийся с '/'"
"subKeyPath" = "Путь к файлу закрытого ключа сертификата подписки" "subKeyPath" = "Путь к файлу закрытого ключа сертификата подписки"
"subKeyPathDesc" = "Введите абсолютный путь, начинающийся с '/'" "subKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
"subPath" = "Корневой путь URL-адреса подписки" "subPath" = "Корневой путь URL-адреса подписки"
"subPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'" "subPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'"
"subDomain" = "Домен прослушивания" "subDomain" = "Домен прослушивания"
"subDomainDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все домены и IP-адреса" "subDomainDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все домены и IP-адреса"
"subUpdates" = "Интервалы обновления подписки" "subUpdates" = "Интервалы обновления подписки"
"subUpdatesDesc" = "Часовой интервал между обновлениями в клиентском приложении" "subUpdatesDesc" = "Интервал между обновлениями в клиентском приложении (в часах)"
"subEncrypt" = "Шифровать конфиги" "subEncrypt" = "Шифровать конфиги"
"subEncryptDesc" = "Шифровать возвращенные конфиги в подписке" "subEncryptDesc" = "Шифровать возвращенные конфиги в подписке"
"subShowInfo" = "Показать информацию об использовании" "subShowInfo" = "Показать информацию об использовании"
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации" "subShowInfoDesc" = "Показывать оставшиеся трафик и дату после имени конфигурации"
"subURI" = "URI обратного прокси" "subURI" = "URI обратного прокси"
"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами" "subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами"
"fragment" = "Фрагментация" "fragment" = "Фрагментация"
@ -327,7 +329,7 @@
"generalConfigs" = "Основные настройки" "generalConfigs" = "Основные настройки"
"generalConfigsDesc" = "Эти параметры описывают общие настройки" "generalConfigsDesc" = "Эти параметры описывают общие настройки"
"logConfigs" = "Журнал" "logConfigs" = "Журнал"
"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их с умом только в случае ваших нужд!" "logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их только в случае необходимости!"
"blockConfigs" = "Блокировка конфигураций" "blockConfigs" = "Блокировка конфигураций"
"blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам" "blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам"
"basicRouting" = "Базовые соединения" "basicRouting" = "Базовые соединения"
@ -344,7 +346,7 @@
"Template" = "Шаблон конфигурации Xray" "Template" = "Шаблон конфигурации Xray"
"TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона" "TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона"
"FreedomStrategy" = "Настройка стратегии протокола Freedom" "FreedomStrategy" = "Настройка стратегии протокола Freedom"
"FreedomStrategyDesc" = "Установка стратегию вывода сети в протоколе Freedom" "FreedomStrategyDesc" = "Установка стратегии вывода сети в протоколе Freedom"
"RoutingStrategy" = "Настройка стратегии маршрутизации доменов" "RoutingStrategy" = "Настройка стратегии маршрутизации доменов"
"RoutingStrategyDesc" = "Установка общей стратегии маршрутизации разрешения DNS" "RoutingStrategyDesc" = "Установка общей стратегии маршрутизации разрешения DNS"
"Torrent" = "Запрет использования BitTorrent" "Torrent" = "Запрет использования BitTorrent"
@ -362,7 +364,7 @@
"logLevel" = "Уровень журнала" "logLevel" = "Уровень журнала"
"logLevelDesc" = "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать." "logLevelDesc" = "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать."
"accessLog" = "Журнал доступа" "accessLog" = "Журнал доступа"
"accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключило журналы доступа." "accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключает журналы доступа."
"errorLog" = "Журнал ошибок" "errorLog" = "Журнал ошибок"
"errorLogDesc" = "Путь к файлу журнала ошибок. Специальное значение «none» отключает журналы ошибок." "errorLogDesc" = "Путь к файлу журнала ошибок. Специальное значение «none» отключает журналы ошибок."
"dnsLog" = "DNS Журнал" "dnsLog" = "DNS Журнал"
@ -379,7 +381,7 @@
"dest" = "Пункт назначения" "dest" = "Пункт назначения"
"inbound" = "Входящий" "inbound" = "Входящий"
"outbound" = "Исходящий" "outbound" = "Исходящий"
"balancer" = "балансир" "balancer" = "Балансировщик"
"info" = "Информация" "info" = "Информация"
"add" = "Добавить правило" "add" = "Добавить правило"
"edit" = "Редактировать правило" "edit" = "Редактировать правило"
@ -391,7 +393,7 @@
"editOutbound" = "Изменить исходящий" "editOutbound" = "Изменить исходящий"
"editReverse" = "Редактировать реверс" "editReverse" = "Редактировать реверс"
"tag" = "Тег" "tag" = "Тег"
"tagDesc" = "уникальный тег" "tagDesc" = "Уникальный тег"
"address" = "Адрес" "address" = "Адрес"
"reverse" = "Обратный" "reverse" = "Обратный"
"domain" = "Домен" "domain" = "Домен"
@ -400,21 +402,21 @@
"portal" = "Портал" "portal" = "Портал"
"intercon" = "Соединение" "intercon" = "Соединение"
"settings" = "Настройки" "settings" = "Настройки"
"accountInfo" = "Информация Об Учетной Записи" "accountInfo" = "Информация Об учетной записи"
"outboundStatus" = "Исходящий статус" "outboundStatus" = "Исходящий статус"
"sendThrough" = "Отправить через" "sendThrough" = "Отправить через"
[pages.xray.balancer] [pages.xray.balancer]
"addBalancer" = "Добавить балансир" "addBalancer" = "Добавить балансировщик"
"editBalancer" = "Редактировать балансир" "editBalancer" = "Редактировать балансировщик"
"balancerStrategy" = "Стратегия" "balancerStrategy" = "Стратегия"
"balancerSelectors" = "Селекторы" "balancerSelectors" = "Селекторы"
"tag" = "Тег" "tag" = "Тег"
"tagDesc" = "уникальный тег" "tagDesc" = "Уникальный тег"
"balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag." "balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
[pages.xray.wireguard] [pages.xray.wireguard]
"secretKey" = "Секретный ключ" "secretKey" = "Приватный ключ"
"publicKey" = "Публичный ключ" "publicKey" = "Публичный ключ"
"allowedIPs" = "Разрешенные IP-адреса" "allowedIPs" = "Разрешенные IP-адреса"
"endpoint" = "Конечная точка" "endpoint" = "Конечная точка"
@ -483,8 +485,12 @@
"status" = "✅ Бот работает нормально!" "status" = "✅ Бот работает нормально!"
"usage" = "❗ Пожалуйста, укажите текст для поиска!" "usage" = "❗ Пожалуйста, укажите текст для поиска!"
"getID" = "🆔 Ваш ID: <code>{{ .ID }}</code>" "getID" = "🆔 Ваш ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Для поиска электронной почты клиента:\r\n<code>/usage [Email]</code>\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n<code>/inbound [Примечание]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>" "helpAdminCommands" = "Для перезапуска Xray Core:\r\n<code>/restart force</code>\r\n\r\nДля поиска электронной почты клиента:\r\n<code>/usage [Email]</code>\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n<code>/inbound [Примечание]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>"
"helpClientCommands" = "Для поиска статистики используйте следующую команду:\r\n<code>/usage [Email]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>" "helpClientCommands" = "Для поиска статистики используйте следующую команду:\r\n<code>/usage [Email]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Операция успешно завершена!"
"restartFailed" = "❗ Ошибка в операции.\r\n\r\n<code>Ошибка: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core не запущен."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%" "cpuThreshold" = "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "'@BotFather'dan alınan Telegram bot token." "telegramTokenDesc" = "'@BotFather'dan alınan Telegram bot token."
"telegramProxy" = "SOCKS Proxy" "telegramProxy" = "SOCKS Proxy"
"telegramProxyDesc" = "Telegram'a bağlanmak için SOCKS5 proxy'sini etkinleştirir. (ayarları kılavuzda belirtilen şekilde ayarlayın)" "telegramProxyDesc" = "Telegram'a bağlanmak için SOCKS5 proxy'sini etkinleştirir. (ayarları kılavuzda belirtilen şekilde ayarlayın)"
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "Kullanılacak Telegram API sunucusu. Varsayılan sunucuyu kullanmak için boş bırakın."
"telegramChatId" = "Yönetici Sohbet Kimliği" "telegramChatId" = "Yönetici Sohbet Kimliği"
"telegramChatIdDesc" = "Telegram Yönetici Sohbet Kimliği(leri). (virgülle ayrılmış)(buradan alın @userinfobot) veya (botta '/id' komutunu kullanın)" "telegramChatIdDesc" = "Telegram Yönetici Sohbet Kimliği(leri). (virgülle ayrılmış)(buradan alın @userinfobot) veya (botta '/id' komutunu kullanın)"
"telegramNotifyTime" = "Bildirim Zamanı" "telegramNotifyTime" = "Bildirim Zamanı"
@ -483,8 +485,12 @@
"status" = "✅ Bot çalışıyor!" "status" = "✅ Bot çalışıyor!"
"usage" = "❗ Lütfen aramak için bir metin sağlayın!" "usage" = "❗ Lütfen aramak için bir metin sağlayın!"
"getID" = "🆔 Kimliğiniz: <code>{{ .ID }}</code>" "getID" = "🆔 Kimliğiniz: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Bir müşteri e-postasını aramak için:\r\n<code>/usage [E-posta]</code>\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n<code>/inbound [Açıklama]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>" "helpAdminCommands" = "Xray Core'u yeniden başlatmak için:\r\n<code>/restart force</code>\r\n\r\nBir müşteri e-postasını aramak için:\r\n<code>/usage [E-posta]</code>\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n<code>/inbound [Açıklama]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>"
"helpClientCommands" = "İstatistikleri aramak için şu komutu kullanın:\r\n\r\n<code>/usage [E-posta]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>" "helpClientCommands" = "İstatistikleri aramak için şu komutu kullanın:\r\n\r\n<code>/usage [E-posta]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ İşlem başarılı!"
"restartFailed" = "❗ İşlem hatası.\r\n\r\n<code>Hata: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core çalışmıyor."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 CPU Yükü {{ .Percent }}% eşiği {{ .Threshold }}%'yi aşıyor" "cpuThreshold" = "🔴 CPU Yükü {{ .Percent }}% eşiği {{ .Threshold }}%'yi aşıyor"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "Токен бота Telegram, отриманий від '@BotFather'." "telegramTokenDesc" = "Токен бота Telegram, отриманий від '@BotFather'."
"telegramProxy" = "SOCKS Проксі" "telegramProxy" = "SOCKS Проксі"
"telegramProxyDesc" = "Вмикає проксі-сервер SOCKS5 для підключення до Telegram. (відкоригуйте параметри відповідно до посібника)" "telegramProxyDesc" = "Вмикає проксі-сервер SOCKS5 для підключення до Telegram. (відкоригуйте параметри відповідно до посібника)"
"telegramAPIServer" = "Сервер Telegram API"
"telegramAPIServerDesc" = "Сервер Telegram API для використання. Залиште поле порожнім, щоб використовувати сервер за умовчанням."
"telegramChatId" = "Ідентифікатор чату адміністратора" "telegramChatId" = "Ідентифікатор чату адміністратора"
"telegramChatIdDesc" = "Ідентифікатори чату адміністратора Telegram. (розділені комами) (отримайте тут @userinfobot) або (використовуйте команду '/id' у боті)" "telegramChatIdDesc" = "Ідентифікатори чату адміністратора Telegram. (розділені комами) (отримайте тут @userinfobot) або (використовуйте команду '/id' у боті)"
"telegramNotifyTime" = "Час сповіщення" "telegramNotifyTime" = "Час сповіщення"
@ -483,8 +485,12 @@
"status" = "✅ Бот в порядку!" "status" = "✅ Бот в порядку!"
"usage" = "❗ Введіть текст для пошуку!" "usage" = "❗ Введіть текст для пошуку!"
"getID" = "🆔 Ваш ідентифікатор: <code>{{ .ID }}</code>" "getID" = "🆔 Ваш ідентифікатор: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Для пошуку електронної пошти клієнта:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n<code>/inbound [Примітка]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>" "helpAdminCommands" = "Для перезапуску Xray Core:\r\n<code>/restart force</code>\r\n\r\nДля пошуку електронної пошти клієнта:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n<code>/inbound [Примітка]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>"
"helpClientCommands" = "Для пошуку статистики використовуйте наступну команду:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>" "helpClientCommands" = "Для пошуку статистики використовуйте наступну команду:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Операція успішна!"
"restartFailed" = "❗ Помилка в операції.\r\n\r\n<code>Помилка: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core не запущений."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 Навантаження ЦП {{ .Percent }}% перевищує порогове значення {{ .Threshold }}%" "cpuThreshold" = "🔴 Навантаження ЦП {{ .Percent }}% перевищує порогове значення {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "Bạn phải nhận token từ quản lý bot Telegram @botfather" "telegramTokenDesc" = "Bạn phải nhận token từ quản lý bot Telegram @botfather"
"telegramProxy" = "Socks5 Proxy" "telegramProxy" = "Socks5 Proxy"
"telegramProxyDesc" = "Nếu bạn cần socks5 proxy để kết nối với Telegram. Điều chỉnh cài đặt của nó theo hướng dẫn." "telegramProxyDesc" = "Nếu bạn cần socks5 proxy để kết nối với Telegram. Điều chỉnh cài đặt của nó theo hướng dẫn."
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "Máy chủ API Telegram để sử dụng. Để trống để sử dụng máy chủ mặc định."
"telegramChatId" = "Chat ID Telegram của quản trị viên" "telegramChatId" = "Chat ID Telegram của quản trị viên"
"telegramChatIdDesc" = "Nhiều Chat ID phân tách bằng dấu phẩy. Sử dụng @userinfobot hoặc sử dụng lệnh '/id' trong bot để lấy Chat ID của bạn." "telegramChatIdDesc" = "Nhiều Chat ID phân tách bằng dấu phẩy. Sử dụng @userinfobot hoặc sử dụng lệnh '/id' trong bot để lấy Chat ID của bạn."
"telegramNotifyTime" = "Thời gian thông báo của bot Telegram" "telegramNotifyTime" = "Thời gian thông báo của bot Telegram"
@ -483,8 +485,12 @@
"status" = "✅ Bot hoạt động bình thường!" "status" = "✅ Bot hoạt động bình thường!"
"usage" = "❗ Vui lòng cung cấp văn bản để tìm kiếm!" "usage" = "❗ Vui lòng cung cấp văn bản để tìm kiếm!"
"getID" = "🆔 ID của bạn: <code>{{ .ID }}</code>" "getID" = "🆔 ID của bạn: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Để tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n\r\nĐể tìm kiếm các nhập (với số liệu thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>" "helpAdminCommands" = "Để khởi động lại Xray Core:\r\n<code>/restart force</code>\r\n\r\nĐể tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n\r\nĐể tìm kiếm các nhập (với số liệu thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>"
"helpClientCommands" = "Để tìm kiếm thống kê, sử dụng lệnh sau:\r\n<code>/usage [Email]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>" "helpClientCommands" = "Để tìm kiếm thống kê, sử dụng lệnh sau:\r\n<code>/usage [Email]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ Hoạt động thành công!"
"restartFailed" = "❗ Lỗi trong quá trình hoạt động.\r\n\r\n<code>Lỗi: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core không chạy."
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%" "cpuThreshold" = "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "从 '@BotFather' 获取的 Telegram 机器人令牌" "telegramTokenDesc" = "从 '@BotFather' 获取的 Telegram 机器人令牌"
"telegramProxy" = "SOCKS5 Proxy" "telegramProxy" = "SOCKS5 Proxy"
"telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram根据指南调整设置" "telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram根据指南调整设置"
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "要使用的 Telegram API 服务器。留空以使用默认服务器。"
"telegramChatId" = "管理员聊天 ID" "telegramChatId" = "管理员聊天 ID"
"telegramChatIdDesc" = "Telegram 管理员聊天 ID (多个以逗号分隔)(可通过 @userinfobot 获取,或在机器人中使用 '/id' 命令获取)" "telegramChatIdDesc" = "Telegram 管理员聊天 ID (多个以逗号分隔)(可通过 @userinfobot 获取,或在机器人中使用 '/id' 命令获取)"
"telegramNotifyTime" = "通知时间" "telegramNotifyTime" = "通知时间"
@ -483,8 +485,12 @@
"status" = "✅ 机器人正常运行!" "status" = "✅ 机器人正常运行!"
"usage" = "❗ 请输入要搜索的文本!" "usage" = "❗ 请输入要搜索的文本!"
"getID" = "🆔 您的 ID 为:<code>{{ .ID }}</code>" "getID" = "🆔 您的 ID 为:<code>{{ .ID }}</code>"
"helpAdminCommands" = "要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站带有客户统计数据\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>" "helpAdminCommands" = "要重新启动 Xray Core\r\n<code>/restart force</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站带有客户统计数据\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>"
"helpClientCommands" = "要搜索统计数据,请使用以下命令:\r\n<code>/usage [电子邮件]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>" "helpClientCommands" = "要搜索统计数据,请使用以下命令:\r\n<code>/usage [电子邮件]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ 操作成功!"
"restartFailed" = "❗ 操作错误。\r\n\r\n<code>错误: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core 未运行。"
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%" "cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%"

View file

@ -265,6 +265,8 @@
"telegramTokenDesc" = "從 '@BotFather' 獲取的 Telegram 機器人令牌" "telegramTokenDesc" = "從 '@BotFather' 獲取的 Telegram 機器人令牌"
"telegramProxy" = "SOCKS5 Proxy" "telegramProxy" = "SOCKS5 Proxy"
"telegramProxyDesc" = "啟用 SOCKS5 代理連線到 Telegram根據指南調整設定" "telegramProxyDesc" = "啟用 SOCKS5 代理連線到 Telegram根據指南調整設定"
"telegramAPIServer" = "Telegram API Server"
"telegramAPIServerDesc" = "要使用的 Telegram API 伺服器。留空以使用預設伺服器。"
"telegramChatId" = "管理員聊天 ID" "telegramChatId" = "管理員聊天 ID"
"telegramChatIdDesc" = "Telegram 管理員聊天 ID (多個以逗號分隔)(可通過 @userinfobot 獲取,或在機器人中使用 '/id' 命令獲取)" "telegramChatIdDesc" = "Telegram 管理員聊天 ID (多個以逗號分隔)(可通過 @userinfobot 獲取,或在機器人中使用 '/id' 命令獲取)"
"telegramNotifyTime" = "通知時間" "telegramNotifyTime" = "通知時間"
@ -483,8 +485,12 @@
"status" = "✅ 機器人正常執行!" "status" = "✅ 機器人正常執行!"
"usage" = "❗ 請輸入要搜尋的文字!" "usage" = "❗ 請輸入要搜尋的文字!"
"getID" = "🆔 您的 ID 為:<code>{{ .ID }}</code>" "getID" = "🆔 您的 ID 為:<code>{{ .ID }}</code>"
"helpAdminCommands" = "要搜尋客戶電子郵件:\r\n<code>/usage [電子郵件]</code>\r\n\r\n要搜尋入站帶有客戶統計資料\r\n<code>/inbound [備註]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>" "helpAdminCommands" = "要重新啟動 Xray Core\r\n<code>/restart force</code>\r\n\r\n要搜尋客戶電子郵件:\r\n<code>/usage [電子郵件]</code>\r\n\r\n要搜尋入站帶有客戶統計資料\r\n<code>/inbound [備註]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>"
"helpClientCommands" = "要搜尋統計資料,請使用以下命令:\r\n<code>/usage [電子郵件]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>" "helpClientCommands" = "要搜尋統計資料,請使用以下命令:\r\n<code>/usage [電子郵件]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>"
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
"restartSuccess" = "✅ 操作成功!"
"restartFailed" = "❗ 操作錯誤。\r\n\r\n<code>錯誤: {{ .Error }}</code>."
"xrayNotRunning" = "❗ Xray Core 未運行。"
[tgbot.messages] [tgbot.messages]
"cpuThreshold" = "🔴 CPU 使用率為 {{ .Percent }}%,超過閾值 {{ .Threshold }}%" "cpuThreshold" = "🔴 CPU 使用率為 {{ .Percent }}%,超過閾值 {{ .Threshold }}%"

29
x-ui.sh
View file

@ -416,10 +416,31 @@ disable() {
} }
show_log() { show_log() {
journalctl -u x-ui.service -e --no-pager -f echo -e "${green}\t1.${plain} Debug Log"
if [[ $# == 0 ]]; then echo -e "${green}\t2.${plain} Clear All logs"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
0)
return
;;
1)
journalctl -u x-ui -e --no-pager -f -p debug
if [[ $# == 0 ]]; then
before_show_menu before_show_menu
fi fi
;;
2)
sudo journalctl --rotate
sudo journalctl --vacuum-time=1s
echo "All Logs cleared."
restart
;;
*)
echo "Invalid choice"
;;
esac
} }
show_banlog() { show_banlog() {
@ -1449,7 +1470,7 @@ show_menu() {
${green}12.${plain} Stop ${green}12.${plain} Stop
${green}13.${plain} Restart ${green}13.${plain} Restart
${green}14.${plain} Check Status ${green}14.${plain} Check Status
${green}15.${plain} Check Logs ${green}15.${plain} Logs Management
———————————————— ————————————————
${green}16.${plain} Enable Autostart ${green}16.${plain} Enable Autostart
${green}17.${plain} Disable Autostart ${green}17.${plain} Disable Autostart