diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 731a916a..38ee449f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -83,7 +83,7 @@ jobs: cd x-ui/bin # 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 wget ${Xray_URL}Xray-linux-64.zip unzip Xray-linux-64.zip diff --git a/DockerInit.sh b/DockerInit.sh index b68af92f..aae6b1c4 100755 --- a/DockerInit.sh +++ b/DockerInit.sh @@ -27,7 +27,7 @@ case $1 in esac mkdir -p 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" rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat mv xray "xray-linux-${FNAME}" diff --git a/README.es_ES.md b/README.es_ES.md index e5009057..dc096a24 100644 --- a/README.es_ES.md +++ b/README.es_ES.md @@ -30,38 +30,62 @@ 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
- Haz clic para el Certificado SSL + Haga clic para ver los detalles del certificado SSL -### 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 -- Clave Global de API de Cloudflare -- El nombre de dominio se ha resuelto en el servidor actual a través de Cloudflare - -**1:** Ejecuta el comando`x-ui`en la terminal, luego elige `Certificado SSL de Cloudflare`. +1. Asegúrate de que tu dominio esté correctamente resuelto al servidor. +2. Ejecuta el comando `x-ui` en la terminal y elige `Gestión de Certificados SSL`. +3. Se te presentarán las siguientes opciones: + - **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 -``` + +Para instalar y usar Certbot: + +```sh apt-get install certbot -y certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com 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)
diff --git a/README.md b/README.md index 67ccee31..6f52f0ce 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ 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 @@ -54,6 +54,8 @@ To manage SSL certificates using ACME: - **Get SSL:** Obtain SSL certificates. - **Revoke:** Revoke existing 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 diff --git a/README.ru_RU.md b/README.ru_RU.md index 20e108bb..36ad3ced 100644 --- a/README.ru_RU.md +++ b/README.ru_RU.md @@ -30,12 +30,12 @@ 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 Сертификат @@ -54,6 +54,8 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. - **Get SSL:** Получить SSL сертификаты. - **Revoke:** Отозвать существующие SSL сертификаты. - **Force Renew:** Принудительно перевыпустить SSL сертификаты. + - **Show Existing Domains:** Отобразить все сертификаты доменов, доступные на сервере. + - **Set Certificate Paths for the Panel:** Укажите сертификат для вашего домена, который будет использоваться панелью. ### Certbot diff --git a/README.zh_CN.md b/README.zh_CN.md index dda0651e..c4fe7d86 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -30,12 +30,12 @@ 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证书 @@ -51,9 +51,11 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. 2. 在终端中运行 `x-ui` 命令,然后选择 `SSL证书管理`。 3. 您将看到以下选项: - - **获取SSL证书:** 获取SSL证书。 - - **吊销:** 吊销现有的SSL证书。 - - **强制更新:** 强制更新SSL证书。 + - **Get SSL:** 获取SSL证书。 + - **Revoke:** 吊销现有的SSL证书。 + - **Force Renew:** 强制更新SSL证书。 + - **Show Existing Domains:** 显示服务器上所有可用的域证书。 + - **Set Certificate Paths for the Panel:** 指定用于面板的域证书。 ### Certbot diff --git a/config/version b/config/version index ab6d2789..26f8b8bc 100644 --- a/config/version +++ b/config/version @@ -1 +1 @@ -2.4.4 \ No newline at end of file +2.4.5 \ No newline at end of file diff --git a/go.mod b/go.mod index 402feeb2..1107a9ae 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/gin-gonic/gin v1.10.0 github.com/goccy/go-json v0.10.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/pelletier/go-toml/v2 v2.2.3 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/ebitengine/purego v0.8.0 // 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/go-ole/go-ole v1.3.0 // 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/now v1.1.5 // 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/kr/text v0.2.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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // 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/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect @@ -94,7 +94,7 @@ require ( golang.org/x/tools v0.26.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // 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 gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect diff --git a/go.sum b/go.sum index 65f127fe..d69876a7 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +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/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM= 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/fasthttp/router v1.5.2 h1:ckJCCdV7hWkkrMeId3WfEhz+4Gyyf6QPwxi/RHIMZ6I= 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.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +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/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 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.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +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.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= 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/mymmrac/telego v0.31.3 h1:yZlD+dm+1W6p3OmCG8K+MbS02Y6paUgwPnqfZN3RWQQ= 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.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= +github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g= +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/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= 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/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/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= -github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= +github.com/quic-go/quic-go v0.48.0 h1:2TCyvBrMu1Z25rvIAlnp2dPT4lgh/uTqLqiXVpp5AeU= +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/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= 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/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= 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-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +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/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= diff --git a/install.sh b/install.sh index f3bc01d6..a5c9c4dd 100644 --- a/install.sh +++ b/install.sh @@ -137,46 +137,61 @@ gen_random_string() { } 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 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) if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then - read -p "Please set up the panel port: " config_port 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 Web Base Path will be generated randomly: ${config_webBasePath}${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 "###############################################" - echo -e "${green}Username: ${config_account}${plain}" + echo -e "${green}Username: ${config_username}${plain}" echo -e "${green}Password: ${config_password}${plain}" echo -e "${green}Port: ${config_port}${plain}" echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" echo -e "###############################################" - else - echo -e "${red}Cancel...${plain}" if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then - 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 "###############################################" - echo -e "${green}Username: ${config_account}${plain}" + echo -e "${green}Username: ${config_username}${plain}" echo -e "${green}Password: ${config_password}${plain}" echo -e "${green}Port: ${portTemp}${plain}" echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" @@ -185,14 +200,6 @@ config_after_install() { 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}" - 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 diff --git a/sub/default.json b/sub/default.json index 32948c77..931259ec 100644 --- a/sub/default.json +++ b/sub/default.json @@ -47,7 +47,9 @@ "tag": "direct", "protocol": "freedom", "settings": { - "domainStrategy": "UseIP" + "domainStrategy": "UseIP", + "redirect": "", + "noises": [] } }, { diff --git a/util/common/format.go b/util/common/format.go index 1ea10877..c73e3a01 100644 --- a/util/common/format.go +++ b/util/common/format.go @@ -4,18 +4,14 @@ import ( "fmt" ) -func FormatTraffic(trafficBytes int64) (size string) { - if trafficBytes < 1024 { - return fmt.Sprintf("%.2fB", float64(trafficBytes)/float64(1)) - } else if trafficBytes < (1024 * 1024) { - return fmt.Sprintf("%.2fKB", float64(trafficBytes)/float64(1024)) - } else if trafficBytes < (1024 * 1024 * 1024) { - return fmt.Sprintf("%.2fMB", float64(trafficBytes)/float64(1024*1024)) - } else if trafficBytes < (1024 * 1024 * 1024 * 1024) { - 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)) +func FormatTraffic(trafficBytes int64) string { + units := []string{"B", "KB", "MB", "GB", "TB", "PB"} + unitIndex := 0 + size := float64(trafficBytes) + + for size >= 1024 && unitIndex < len(units)-1 { + size /= 1024 + unitIndex++ } + return fmt.Sprintf("%.2f%s", size, units[unitIndex]) } diff --git a/web/assets/js/model/dbinbound.js b/web/assets/js/model/dbinbound.js index 9f6f04c6..aeae1a75 100644 --- a/web/assets/js/model/dbinbound.js +++ b/web/assets/js/model/dbinbound.js @@ -140,9 +140,9 @@ class DBInbound { return false; } } - - genInboundLinks(remarkModel) { + + genInboundLinks(remarkModel) { const inbound = this.toInbound(); - return inbound.genInboundLinks(this.remark,remarkModel); + return inbound.genInboundLinks(this.remark, remarkModel); } } \ No newline at end of file diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index a66cc215..4f8a8273 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -890,7 +890,11 @@ Outbound.FreedomSettings = class extends CommonClass { }; Outbound.FreedomSettings.Fragment = class extends CommonClass { - constructor(packets = '1-3', length = '', interval = '') { + constructor( + packets = '1-3', + length = '', + interval = '' + ) { super(); this.packets = packets; this.length = length; @@ -1178,7 +1182,8 @@ Outbound.WireguardSettings = class extends CommonClass { domainStrategy = '', reserved = '', peers = [new Outbound.WireguardSettings.Peer()], - kernelMode = false + kernelMode = false, + kernelTun = false ) { super(); this.mtu = mtu; @@ -1190,6 +1195,7 @@ Outbound.WireguardSettings = class extends CommonClass { this.reserved = Array.isArray(reserved) ? reserved.join(',') : reserved; this.peers = peers; this.kernelMode = kernelMode; + this.kernelTun = kernelTun; } addPeer() { @@ -1210,6 +1216,7 @@ Outbound.WireguardSettings = class extends CommonClass { json.reserved, json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)), json.kernelMode, + json.kernelTun, ); } @@ -1223,6 +1230,7 @@ Outbound.WireguardSettings = class extends CommonClass { reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined, peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers), kernelMode: this.kernelMode, + kernelTun: this.kernelTun, }; } }; diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js index b73d6008..6282518c 100644 --- a/web/assets/js/model/setting.js +++ b/web/assets/js/model/setting.js @@ -16,6 +16,7 @@ class AllSetting { this.tgBotEnable = false; this.tgBotToken = ""; this.tgBotProxy = ""; + this.tgBotAPIServer = ""; this.tgBotChatId = ""; this.tgRunTime = "@daily"; this.tgBotBackup = false; diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 6d0c1c9d..3e99ef34 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -529,10 +529,10 @@ class SplitHTTPStreamSettings extends XrayCommonClass { scMinPostsIntervalMs = "10-50", noSSEHeader = false, xPaddingBytes = "100-1000", - xmux = { - maxConcurrency: 0, + xmux = { + maxConcurrency: "16-32", maxConnections: 0, - cMaxReuseTimes: 0, + cMaxReuseTimes: "64-128", cMaxLifetimeMs: 0 } ) { @@ -545,7 +545,7 @@ class SplitHTTPStreamSettings extends XrayCommonClass { this.scMinPostsIntervalMs = scMinPostsIntervalMs; this.noSSEHeader = noSSEHeader; this.xPaddingBytes = xPaddingBytes; - this.xmux = xmux; + this.xmux = xmux; } addHeader(name, value) { @@ -909,7 +909,7 @@ class RealityStreamSettings extends XrayCommonClass { this.minClient = minClient; this.maxClient = maxClient; this.maxTimediff = maxTimediff; - this.shortIds = Array.isArray(shortIds) ? shortIds.join(",") : shortIds; + this.shortIds = Array.isArray(shortIds) ? shortIds.join(",") : shortIds; this.settings = settings; } @@ -920,7 +920,9 @@ class RealityStreamSettings extends XrayCommonClass { json.settings.publicKey, json.settings.fingerprint, json.settings.serverName, - json.settings.spiderX);} + json.settings.spiderX + ); + } return new RealityStreamSettings( json.show, json.xver, @@ -2598,7 +2600,7 @@ Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass { Inbound.HttpSettings = class extends Inbound.Settings { constructor( - protocol, + protocol, accounts = [new Inbound.HttpSettings.HttpAccount()], allowTransparent = false, ) { @@ -2644,13 +2646,21 @@ Inbound.HttpSettings.HttpAccount = 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); this.mtu = mtu; this.secretKey = secretKey; this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : ''; this.peers = peers; this.kernelMode = kernelMode; + this.kernelTun = kernelTun; } addPeer() { @@ -2668,6 +2678,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass { json.secretKey, json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)), json.kernelMode, + json.kernelTun, ); } @@ -2677,6 +2688,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass { secretKey: this.secretKey, peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers), kernelMode: this.kernelMode, + kernelTun: this.kernelTun, }; } }; diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js index 5f20d7d9..779af0bf 100644 --- a/web/assets/js/util/common.js +++ b/web/assets/js/util/common.js @@ -5,9 +5,9 @@ const ONE_TB = ONE_GB * 1024; const ONE_PB = ONE_TB * 1024; function sizeFormat(size) { - if (size < 0) { - return "0 B"; - } else if (size < ONE_KB) { + if (size <= 0) return "0 B"; + + if (size < ONE_KB) { return size.toFixed(0) + " B"; } else if (size < ONE_MB) { return (size / ONE_KB).toFixed(2) + " KB"; @@ -59,7 +59,7 @@ function formatSecond(second) { return (second / 3600).toFixed(0) + 'h'; } else { 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' : ''); } } @@ -149,7 +149,7 @@ function userExpiryColor(threshold, client, isDark = false) { return isDark ? '#2c3950' : '#bcbcbc'; } now = new Date().getTime(), - expiry = client.expiryTime; + expiry = client.expiryTime; switch (true) { case expiry === null: return "#7a316f"; // purple diff --git a/web/entity/entity.go b/web/entity/entity.go index 7e00fbf3..12206340 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -30,6 +30,7 @@ type AllSetting struct { TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` TgBotToken string `json:"tgBotToken" form:"tgBotToken"` TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"` + TgBotAPIServer string `json:"tgBotAPIServer" form:"tgBotAPIServer"` TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` TgRunTime string `json:"tgRunTime" form:"tgRunTime"` TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html index 00b33c0b..f35391cf 100644 --- a/web/html/xui/form/outbound.html +++ b/web/html/xui/form/outbound.html @@ -150,6 +150,9 @@ + + + @@ -898,7 +898,7 @@ bittorrent: ["bittorrent"], }, IPsOptions: [ - { label: 'Private IP', value: 'geoip:private' }, + { label: 'Private IPs', value: 'geoip:private' }, { label: '🇮🇷 Iran', value: 'ext:geoip_IR.dat:ir' }, { label: '🇨🇳 China', value: 'geoip:cn' }, { label: '🇷🇺 Russia', value: 'geoip:ru' }, @@ -910,12 +910,6 @@ { label: '🇧🇷 Brazil', value: 'geoip:br' }, ], 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: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' }, { label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' }, @@ -926,7 +920,13 @@ { label: '🇻🇳 Vietnam', value: 'ext:geosite_VN.dat: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: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' }, { label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' }, diff --git a/web/service/config.json b/web/service/config.json index 122963fe..ea650f7b 100644 --- a/web/service/config.json +++ b/web/service/config.json @@ -30,7 +30,9 @@ "tag": "direct", "protocol": "freedom", "settings": { - "domainStrategy": "UseIP" + "domainStrategy": "UseIP", + "redirect": "", + "noises": [] } }, { diff --git a/web/service/inbound.go b/web/service/inbound.go index 60530143..7afcb140 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -1574,7 +1574,7 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e return false, err } for _, client := range clients { - if client.Email == clientEmail { + if client.Email == clientEmail && client.Enable { s.xrayApi.Init(p.GetAPIPort()) cipher := "" if string(inbound.Protocol) == "shadowsocks" { diff --git a/web/service/setting.go b/web/service/setting.go index 90bf8fc4..bbdac81d 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -41,6 +41,7 @@ var defaultValueMap = map[string]string{ "tgBotEnable": "false", "tgBotToken": "", "tgBotProxy": "", + "tgBotAPIServer": "", "tgBotChatId": "", "tgRunTime": "@daily", "tgBotBackup": "false", @@ -262,6 +263,14 @@ func (s *SettingService) SetTgBotProxy(token string) error { 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) { return s.getString("tgBotChatId") } diff --git a/web/service/tgbot.go b/web/service/tgbot.go index b8294620..7c6780d8 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -108,8 +108,14 @@ func (t *Tgbot) Start(i18nFS embed.FS) error { 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 - bot, err = t.NewBot(tgBotToken, tgBotProxy) + bot, err = t.NewBot(tgBotToken, tgBotProxy, tgBotAPIServer) if err != nil { logger.Error("Failed to initialize Telegram bot API:", err) return err @@ -125,26 +131,40 @@ func (t *Tgbot) Start(i18nFS embed.FS) error { return nil } -func (t *Tgbot) NewBot(token string, proxyUrl string) (*telego.Bot, error) { - if proxyUrl == "" { - // No proxy URL provided, use default instance +func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) { + if proxyUrl == "" && apiServerUrl == "" { return telego.NewBot(token) } - if !strings.HasPrefix(proxyUrl, "socks5://") { - logger.Warning("Invalid socks5 URL, starting with default") + if proxyUrl != "" { + 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) } - _, err := url.Parse(proxyUrl) + _, err := url.Parse(apiServerUrl) 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, telego.WithFastHTTPClient(&fasthttp.Client{ - Dial: fasthttpproxy.FasthttpSocksDialer(proxyUrl), - })) + return telego.NewBot(token, telego.WithAPIServer(apiServerUrl)) } 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) - // 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 { case "help": msg += t.I18nBot("tgbot.commands.help") @@ -266,9 +291,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo if isAdmin { t.searchClient(chatId, commandArgs[0]) } else { - // Convert message.From.ID to int64 - fromID := int64(message.From.ID) - t.getClientUsage(chatId, fromID, commandArgs[0]) + t.getClientUsage(chatId, int64(message.From.ID), commandArgs[0]) } } else { 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 { t.searchInbound(chatId, commandArgs[0]) } 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: - msg += t.I18nBot("tgbot.commands.unknown") + handleUnknownCommand() } if msg != "" { - if onlyMessage { - t.SendMsgToTgbot(chatId, msg) - return - } else { - t.SendAnswer(chatId, msg, isAdmin) - } + t.sendResponse(chatId, msg, onlyMessage, 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.allClients")).WithCallbackData(t.encodeQuery("get_inbounds")), ), + // TODOOOOOOOOOOOOOO: Add restart button here. ) numericKeyboardClient := tu.InlineKeyboard( tu.InlineKeyboardRow( diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index 7e2e5eef..d10d0f3c 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'." "telegramProxy" = "SOCKS Proxy" "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" "telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(get it here @userinfobot) or (use '/id' command in the bot)" "telegramNotifyTime" = "Notification Time" @@ -483,8 +485,12 @@ "status" = "✅ Bot is OK!" "usage" = "❗ Please provide a text to search!" "getID" = "🆔 Your ID: {{ .ID }}" -"helpAdminCommands" = "To search for a client email:\r\n/usage [Email]\r\n\r\nTo search for inbounds (with client stats):\r\n/inbound [Remark]\r\n\r\nTelegram Chat ID:\r\n/id" +"helpAdminCommands" = "To restart Xray Core:\r\n/restart force\r\n\r\nTo search for a client email:\r\n/usage [Email]\r\n\r\nTo search for inbounds (with client stats):\r\n/inbound [Remark]\r\n\r\nTelegram Chat ID:\r\n/id" "helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n/usage [Email]\r\n\r\nTelegram Chat ID:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Operation successful!" +"restartFailed" = "❗ Error in operation.\r\n\r\nError: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core is not running." [tgbot.messages] "cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%" diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index 1ca7a505..68797735 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "Debe obtener el token del administrador de bots de Telegram @botfather." "telegramProxy" = "Socks5 Proxy" "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" "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" @@ -483,8 +485,12 @@ "status" = "✅ ¡El bot está bien!" "usage" = "❗ ¡Por favor proporciona un texto para buscar!" "getID" = "🆔 Tu ID: {{ .ID }}" -"helpAdminCommands" = "Para buscar un correo electrónico de cliente:\r\n/usage [Correo electrónico]\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n/inbound [Observación]\r\n\r\nID de Chat de Telegram:\r\n/id" +"helpAdminCommands" = "Para reiniciar Xray Core:\r\n/restart force\r\n\r\nPara buscar un correo electrónico de cliente:\r\n/usage [Correo electrónico]\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n/inbound [Observación]\r\n\r\nID de Chat de Telegram:\r\n/id" "helpClientCommands" = "Para buscar estadísticas, utiliza el siguiente comando:\r\n/usage [Correo electrónico]\r\n\r\nID de Chat de Telegram:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ ¡Operación exitosa!" +"restartFailed" = "❗ Error en la operación.\r\n\r\nError: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core no está en ejecución." [tgbot.messages] "cpuThreshold" = "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }} : Deshabilitado exitosamente." "askToAddUserId" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su ChatID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu ChatID de usuario: {{ .TgUserID }}" "chooseClient" = "Elige un Cliente para Inbound {{ .Inbound }}" -"chooseInbound" = "Elige un Inbound" \ No newline at end of file +"chooseInbound" = "Elige un Inbound" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index a7ba4a6f..cc893028 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "دریافت کنید @botfather توکن را می‌توانید از" "telegramProxy" = "SOCKS پراکسی" "telegramProxyDesc" = "را برای اتصال به تلگرام فعال می کند SOCKS5 پراکسی" +"telegramAPIServer" = "سرور API تلگرام" +"telegramAPIServerDesc" = "API سرور تلگرام برای اتصال را تغییر میدهد. برای استفاده از سرور پیش فرض خالی بگذارید" "telegramChatId" = "آی‌دی چت مدیر" "telegramChatIdDesc" = "دریافت ‌کنید ('/id'یا (دستور (@userinfobot) آی‌دی(های) چت تلگرام مدیر، از" "telegramNotifyTime" = "زمان نوتیفیکیشن" @@ -483,8 +485,12 @@ "status" = "✅ ربات در حالت عادی است!" "usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!" "getID" = "🆔 شناسه شما: {{ .ID }}" -"helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n/usage [ایمیل]\r\n\r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n/inbound [توضیحات]\r\n\r\nشناسه گفتگوی تلگرام:\r\n/id" +"helpAdminCommands" = "برای راه‌اندازی مجدد Xray Core:\r\n/restart force\r\n\r\nبرای جستجوی ایمیل مشتری:\r\n/usage [ایمیل]\r\n\r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n/inbound [توضیحات]\r\n\r\nشناسه گفتگوی تلگرام:\r\n/id" "helpClientCommands" = "برای جستجوی آمار، از دستور زیر استفاده کنید:\r\n/usage [ایمیل]\r\n\r\nشناسه گفتگوی تلگرام:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ عملیات با موفقیت انجام شد!" +"restartFailed" = "❗ خطا در عملیات.\r\n\r\nخطا: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core در حال اجرا نیست." [tgbot.messages] "cpuThreshold" = "🔴 بار ‌پردازنده {{ .Percent }}% بیشتر از آستانه است {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }} : با موفقیت غیرفعال شد." "askToAddUserId" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nشناسه کاربری شما: {{ .TgUserID }}" "chooseClient" = "یک مشتری برای ورودی {{ .Inbound }} انتخاب کنید" -"chooseInbound" = "یک ورودی انتخاب کنید" \ No newline at end of file +"chooseInbound" = "یک ورودی انتخاب کنید" diff --git a/web/translation/translate.id_ID.toml b/web/translation/translate.id_ID.toml index f543971b..e785c26b 100644 --- a/web/translation/translate.id_ID.toml +++ b/web/translation/translate.id_ID.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "Token bot Telegram yang diperoleh dari '@BotFather'." "telegramProxy" = "Proxy SOCKS" "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" "telegramChatIdDesc" = "ID Obrolan Admin Telegram. (dipisahkan koma)(dapatkan di sini @userinfobot) atau (gunakan perintah '/id' di bot)" "telegramNotifyTime" = "Waktu Notifikasi" @@ -482,9 +484,13 @@ "welcome" = "🤖 Selamat datang di {{.Hostname }} bot managemen.\r\n" "status" = "✅ Bot dalam keadaan baik!" "usage" = "❗ Harap berikan teks untuk mencari!" -"getID" = "🆔 ID Anda:{{.ID }}" -"helpAdminCommands" = "Untuk mencari email klien:\r\n/usage [Email]\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n/inbound [Catatan]\r\n\r\nID Obrolan Telegram:\r\n/id" +"getID" = "🆔 ID Anda: {{ .ID }}" +"helpAdminCommands" = "Untuk memulai ulang Xray Core:\r\n/restart force\r\n\r\nUntuk mencari email klien:\r\n/usage [Email]\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n/inbound [Catatan]\r\n\r\nID Obrolan Telegram:\r\n/id" "helpClientCommands" = "Untuk mencari statistik, gunakan perintah berikut:\r\n/usage [Email]\r\n\r\nID Obrolan Telegram:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Operasi berhasil!" +"restartFailed" = "❗ Kesalahan dalam operasi.\r\n\r\nError: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core tidak berjalan." [tgbot.messages] "cpuThreshold" = "🔴 Beban CPU {{ .Percent }}% melebihi batas {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }}: Dinonaktifkan dengan berhasil." "askToAddUserId" = "Konfigurasi Anda tidak ditemukan!\r\nSilakan minta admin Anda untuk menggunakan ChatID Telegram Anda dalam konfigurasi Anda.\r\n\r\nChatID Pengguna Anda: {{ .TgUserID }}" "chooseClient" = "Pilih Klien untuk Inbound {{ .Inbound }}" -"chooseInbound" = "Pilih Inbound" \ No newline at end of file +"chooseInbound" = "Pilih Inbound" diff --git a/web/translation/translate.pt_BR.toml b/web/translation/translate.pt_BR.toml index f201df66..bbe2bd24 100644 --- a/web/translation/translate.pt_BR.toml +++ b/web/translation/translate.pt_BR.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "O token do bot do Telegram obtido de '@BotFather'." "telegramProxy" = "Proxy SOCKS" "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" "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" @@ -483,8 +485,12 @@ "status" = "✅ Bot está OK!" "usage" = "❗ Por favor, forneça um texto para pesquisar!" "getID" = "🆔 Seu ID: {{ .ID }}" -"helpAdminCommands" = "Para pesquisar por um email de cliente:\r\n/usage [Email]\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n/inbound [Remark]\r\n\r\nTelegram Chat ID:\r\n/id" +"helpAdminCommands" = "Para reiniciar o Xray Core:\r\n/restart force\r\n\r\nPara pesquisar por um email de cliente:\r\n/usage [Email]\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n/inbound [Remark]\r\n\r\nTelegram Chat ID:\r\n/id" "helpClientCommands" = "Para pesquisar por estatísticas, use o seguinte comando:\r\n\r\n/usage [Email]\r\n\r\nTelegram Chat ID:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Operação bem-sucedida!" +"restartFailed" = "❗ Erro na operação.\r\n\r\nErro: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core não está em execução." [tgbot.messages] "cpuThreshold" = "🔴 A carga da CPU {{ .Percent }}% excede o limite de {{ .Threshold }}%" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index 434d481c..7033a7c3 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -1,6 +1,6 @@ "username" = "Имя пользователя" "password" = "Пароль" -"login" = "Логин" +"login" = "Войти" "confirm" = "Подтвердить" "cancel" = "Отмена" "close" = "Закрыть" @@ -67,12 +67,12 @@ "settings" = "Настройки панели" "xray" = "Настройки Xray" "logout" = "Выход" -"link" = "Менеджмент" +"link" = "Управление" [pages.login] "hello" = "Привет" "title" = "Добро пожаловать" -"loginAgain" = "Время пребывания в сети вышло. Пожалуйста, войдите в систему снова" +"loginAgain" = "Ваша сессия истекла. Пожалуйста, войдите в систему снова" [pages.login.toasts] "invalidFormData" = "Недопустимый формат данных" @@ -93,8 +93,8 @@ "xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями" "operationHours" = "Время работы системы" "systemLoad" = "Системная нагрузка" -"systemLoadDesc" = "средняя загрузка системы за последние 1, 5 и 15 минут" -"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам." +"systemLoadDesc" = "Средняя загрузка системы за последние 1, 5 и 15 минут" +"connectionTcpCountDesc" = "Общее количество подключений TCP по всем сетевым картам." "connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам." "connectionCount" = "Количество соединений" "upSpeed" = "Общая скорость upload для всех сетей" @@ -133,21 +133,21 @@ "update" = "Обновить" "modifyInbound" = "Изменить подключение" "deleteInbound" = "Удалить подключение" -"deleteInboundContent" = "Подтвердите удаление подключения?" +"deleteInboundContent" = "Вы уверены, что хотите удалить подключение?" "deleteClient" = "Удалить клиента" "deleteClientContent" = "Вы уверены, что хотите удалить клиента?" -"resetTrafficContent" = "Подтвердите сброс трафика?" +"resetTrafficContent" = "Вы уверены, что хотите сбросить трафик?" "copyLink" = "Копировать ключ" "address" = "Адрес" "network" = "Сеть" "destinationPort" = "Порт назначения" "targetAddress" = "Целевой адрес" -"monitorDesc" = "Оставьте пустым по умолчанию" +"monitorDesc" = "Оставьте пустым для прослушивания всех IP-адресов" "meansNoLimit" = "= Без ограничений (значение: ГБ)" "totalFlow" = "Общий расход" "leaveBlankToNeverExpire" = "Оставьте пустым, чтобы не истекало" -"noRecommendKeepDefault" = "Нет требований для сохранения настроек по умолчанию" -"certificatePath" = "Путь файла" +"noRecommendKeepDefault" = "Рекомендуется оставить настройки по умолчанию" +"certificatePath" = "Путь к файлу" "certificateContent" = "Содержимое файла" "publicKey" = "Публичный ключ" "privatekey" = "Приватный ключ" @@ -160,16 +160,16 @@ "cloneInboundOk" = "Клонировано" "resetAllTraffic" = "Сбросить трафик всех подключений" "resetAllTrafficTitle" = "Сброс трафика всех подключений" -"resetAllTrafficContent" = "Подтверждаете сброс трафика всех подключений?" +"resetAllTrafficContent" = "Вы уверены, что хотите сбросить трафик всех подключений?" "resetInboundClientTraffics" = "Сбросить трафик пользователей" "resetInboundClientTrafficTitle" = "Сброс трафика пользователей" "resetInboundClientTrafficContent" = "Вы уверены, что хотите сбросить весь трафик для этих пользователей?" "resetAllClientTraffics" = "Сбросить трафик всех пользователей" "resetAllClientTrafficTitle" = "Сброс трафика всех пользователей" -"resetAllClientTrafficContent" = "Подтверждаете сброс трафика всех пользователей?" +"resetAllClientTrafficContent" = "Вы уверены, что хотите сбросить трафик всех пользователей?" "delDepletedClients" = "Удалить отключенных пользователей" "delDepletedClientsTitle" = "Удаление отключенных пользователей" -"delDepletedClientsContent" = "Подтверждаете удаление отключенных пользователей?" +"delDepletedClientsContent" = "Вы уверены, что хотите удалить всех отключенных пользователей?" "email" = "Email" "emailDesc" = "Пожалуйста, укажите уникальный Email" "IPLimit" = "Ограничение по IP" @@ -220,7 +220,7 @@ "version" = "Версия" "method" = "Метод" "path" = "Путь" -"status" = "Положение дел" +"status" = "Статус" "statusDescription" = "Описание статуса" "requestHeader" = "Заголовок запроса" "responseHeader" = "Заголовок ответа" @@ -228,9 +228,9 @@ [pages.settings] "title" = "Настройки" "save" = "Сохранить" -"infoDesc" = "Каждое сделанное здесь изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу" +"infoDesc" = "Каждое выполненное изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу" "restartPanel" = "Перезапуск панели" -"restartPanelDesc" = "Подтвердите перезапуск панели? ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере" +"restartPanelDesc" = "Вы уверены, что хотите перезапустить панель?Нажмите ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере" "actions" = "Действия" "resetDefaultConfig" = "Сбросить на конфигурацию по умолчанию" "panelSettings" = "Настройки панели" @@ -243,21 +243,21 @@ "panelPort" = "Порт панели" "panelPortDesc" = "Порт, используемый для отображения этой панели" "publicKeyPath" = "Путь к файлу публичного ключа сертификата панели" -"publicKeyPathDesc" = "Введите полный путь, начинающийся с" +"publicKeyPathDesc" = "Введите полный путь, начинающийся с '/'" "privateKeyPath" = "Путь к файлу приватного ключа сертификата панели" -"privateKeyPathDesc" = "Введите полный путь, начинающийся с" +"privateKeyPathDesc" = "Введите полный путь, начинающийся с '/'" "panelUrlPath" = "Корневой путь URL адреса панели" -"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на" +"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'" "pageSize" = "Размер нумерации страниц" "pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить" "remarkModel" = "Модель примечания и символ разделения" "datepicker" = "Выбор даты" "datepickerPlaceholder" = "Выберите дату" -"datepickerDescription" = "Тип календаря выбора указывает дату истечения срока действия." +"datepickerDescription" = "Запланированные задачи выполняются в соответствии с данным календарём" "sampleRemark" = "Пример замечания" -"oldUsername" = "Текущее имя пользователя" +"oldUsername" = "Текущий логин" "currentPassword" = "Текущий пароль" -"newUsername" = "Новое имя пользователя" +"newUsername" = "Новый логин" "newPassword" = "Новый пароль" "telegramBotEnable" = "Включить Telegram бота" "telegramBotEnableDesc" = "Подключайтесь к функциям этой панели через Telegram бота" @@ -265,8 +265,10 @@ "telegramTokenDesc" = "Необходимо получить токен у менеджера ботов Telegram @botfather" "telegramProxy" = "Прокси Socks5" "telegramProxyDesc" = "Если для подключения к Telegram вам нужен прокси Socks5. Настройте его параметры согласно руководству." -"telegramChatId" = "Telegram ChatID админа бота" -"telegramChatIdDesc" = "Множественные идентификаторы чата, разделенные запятыми. Чтобы получить свои идентификаторы чатов, используйте @userinfobot или команду '/id' в боте." +"telegramAPIServer" = "API-сервер Telegram" +"telegramAPIServerDesc" = "Используемый API-сервер Telegram. Оставьте пустым, чтобы использовать сервер по умолчанию." +"telegramChatId" = "Идентификатор Telegram администратора бота" +"telegramChatIdDesc" = "Один или несколько идентификаторов администратора бота. Чтобы получить идентификатор, используйте @userinfobot или команду '/id' в боте." "telegramNotifyTime" = "Частота уведомлений бота Telegram" "telegramNotifyTimeDesc" = "Используйте формат времени Crontab" "tgNotifyBackup" = "Резервное копирование базы данных" @@ -291,19 +293,19 @@ "subPort" = "Порт подписки" "subPortDesc" = "Номер порта для обслуживания службы подписки не должен использоваться на сервере" "subCertPath" = "Путь к файлу открытого ключа сертификата подписки" -"subCertPathDesc" = "Введите абсолютный путь, начинающийся с '/'" +"subCertPathDesc" = "Введите полный путь, начинающийся с '/'" "subKeyPath" = "Путь к файлу закрытого ключа сертификата подписки" -"subKeyPathDesc" = "Введите абсолютный путь, начинающийся с '/'" +"subKeyPathDesc" = "Введите полный путь, начинающийся с '/'" "subPath" = "Корневой путь URL-адреса подписки" "subPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'" "subDomain" = "Домен прослушивания" "subDomainDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все домены и IP-адреса" "subUpdates" = "Интервалы обновления подписки" -"subUpdatesDesc" = "Часовой интервал между обновлениями в клиентском приложении" +"subUpdatesDesc" = "Интервал между обновлениями в клиентском приложении (в часах)" "subEncrypt" = "Шифровать конфиги" "subEncryptDesc" = "Шифровать возвращенные конфиги в подписке" "subShowInfo" = "Показать информацию об использовании" -"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации" +"subShowInfoDesc" = "Показывать оставшиеся трафик и дату после имени конфигурации" "subURI" = "URI обратного прокси" "subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами" "fragment" = "Фрагментация" @@ -327,7 +329,7 @@ "generalConfigs" = "Основные настройки" "generalConfigsDesc" = "Эти параметры описывают общие настройки" "logConfigs" = "Журнал" -"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их с умом только в случае ваших нужд!" +"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их только в случае необходимости!" "blockConfigs" = "Блокировка конфигураций" "blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам" "basicRouting" = "Базовые соединения" @@ -344,7 +346,7 @@ "Template" = "Шаблон конфигурации Xray" "TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона" "FreedomStrategy" = "Настройка стратегии протокола Freedom" -"FreedomStrategyDesc" = "Установка стратегию вывода сети в протоколе Freedom" +"FreedomStrategyDesc" = "Установка стратегии вывода сети в протоколе Freedom" "RoutingStrategy" = "Настройка стратегии маршрутизации доменов" "RoutingStrategyDesc" = "Установка общей стратегии маршрутизации разрешения DNS" "Torrent" = "Запрет использования BitTorrent" @@ -362,7 +364,7 @@ "logLevel" = "Уровень журнала" "logLevelDesc" = "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать." "accessLog" = "Журнал доступа" -"accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключило журналы доступа." +"accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключает журналы доступа." "errorLog" = "Журнал ошибок" "errorLogDesc" = "Путь к файлу журнала ошибок. Специальное значение «none» отключает журналы ошибок." "dnsLog" = "DNS Журнал" @@ -379,7 +381,7 @@ "dest" = "Пункт назначения" "inbound" = "Входящий" "outbound" = "Исходящий" -"balancer" = "балансир" +"balancer" = "Балансировщик" "info" = "Информация" "add" = "Добавить правило" "edit" = "Редактировать правило" @@ -391,7 +393,7 @@ "editOutbound" = "Изменить исходящий" "editReverse" = "Редактировать реверс" "tag" = "Тег" -"tagDesc" = "уникальный тег" +"tagDesc" = "Уникальный тег" "address" = "Адрес" "reverse" = "Обратный" "domain" = "Домен" @@ -400,21 +402,21 @@ "portal" = "Портал" "intercon" = "Соединение" "settings" = "Настройки" -"accountInfo" = "Информация Об Учетной Записи" +"accountInfo" = "Информация Об учетной записи" "outboundStatus" = "Исходящий статус" "sendThrough" = "Отправить через" [pages.xray.balancer] -"addBalancer" = "Добавить балансир" -"editBalancer" = "Редактировать балансир" +"addBalancer" = "Добавить балансировщик" +"editBalancer" = "Редактировать балансировщик" "balancerStrategy" = "Стратегия" "balancerSelectors" = "Селекторы" "tag" = "Тег" -"tagDesc" = "уникальный тег" +"tagDesc" = "Уникальный тег" "balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag." [pages.xray.wireguard] -"secretKey" = "Секретный ключ" +"secretKey" = "Приватный ключ" "publicKey" = "Публичный ключ" "allowedIPs" = "Разрешенные IP-адреса" "endpoint" = "Конечная точка" @@ -483,8 +485,12 @@ "status" = "✅ Бот работает нормально!" "usage" = "❗ Пожалуйста, укажите текст для поиска!" "getID" = "🆔 Ваш ID: {{ .ID }}" -"helpAdminCommands" = "Для поиска электронной почты клиента:\r\n/usage [Email]\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n/inbound [Примечание]\r\n\r\nID чата Telegram:\r\n/id" +"helpAdminCommands" = "Для перезапуска Xray Core:\r\n/restart force\r\n\r\nДля поиска электронной почты клиента:\r\n/usage [Email]\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n/inbound [Примечание]\r\n\r\nID чата Telegram:\r\n/id" "helpClientCommands" = "Для поиска статистики используйте следующую команду:\r\n/usage [Email]\r\n\r\nID чата Telegram:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Операция успешно завершена!" +"restartFailed" = "❗ Ошибка в операции.\r\n\r\nОшибка: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core не запущен." [tgbot.messages] "cpuThreshold" = "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%" diff --git a/web/translation/translate.tr_TR.toml b/web/translation/translate.tr_TR.toml index 9816111f..ecaf2bab 100644 --- a/web/translation/translate.tr_TR.toml +++ b/web/translation/translate.tr_TR.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "'@BotFather'dan alınan Telegram bot token." "telegramProxy" = "SOCKS Proxy" "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" "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ı" @@ -483,8 +485,12 @@ "status" = "✅ Bot çalışıyor!" "usage" = "❗ Lütfen aramak için bir metin sağlayın!" "getID" = "🆔 Kimliğiniz: {{ .ID }}" -"helpAdminCommands" = "Bir müşteri e-postasını aramak için:\r\n/usage [E-posta]\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n/inbound [Açıklama]\r\n\r\nTelegram Sohbet Kimliği:\r\n/id" +"helpAdminCommands" = "Xray Core'u yeniden başlatmak için:\r\n/restart force\r\n\r\nBir müşteri e-postasını aramak için:\r\n/usage [E-posta]\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n/inbound [Açıklama]\r\n\r\nTelegram Sohbet Kimliği:\r\n/id" "helpClientCommands" = "İstatistikleri aramak için şu komutu kullanın:\r\n\r\n/usage [E-posta]\r\n\r\nTelegram Sohbet Kimliği:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ İşlem başarılı!" +"restartFailed" = "❗ İşlem hatası.\r\n\r\nHata: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core çalışmıyor." [tgbot.messages] "cpuThreshold" = "🔴 CPU Yükü {{ .Percent }}% eşiği {{ .Threshold }}%'yi aşıyor" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }}: Başarıyla devre dışı bırakıldı." "askToAddUserId" = "Yapılandırmanız bulunamadı!\r\nLütfen yöneticinizden yapılandırmalarınıza Telegram ChatID'nizi eklemesini isteyin.\r\n\r\nKullanıcı ChatID'niz: {{ .TgUserID }}" "chooseClient" = "Gelen {{ .Inbound }} için bir Müşteri Seçin" -"chooseInbound" = "Bir Gelen Seçin" \ No newline at end of file +"chooseInbound" = "Bir Gelen Seçin" diff --git a/web/translation/translate.uk_UA.toml b/web/translation/translate.uk_UA.toml index d99b6908..2e584f0e 100644 --- a/web/translation/translate.uk_UA.toml +++ b/web/translation/translate.uk_UA.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "Токен бота Telegram, отриманий від '@BotFather'." "telegramProxy" = "SOCKS Проксі" "telegramProxyDesc" = "Вмикає проксі-сервер SOCKS5 для підключення до Telegram. (відкоригуйте параметри відповідно до посібника)" +"telegramAPIServer" = "Сервер Telegram API" +"telegramAPIServerDesc" = "Сервер Telegram API для використання. Залиште поле порожнім, щоб використовувати сервер за умовчанням." "telegramChatId" = "Ідентифікатор чату адміністратора" "telegramChatIdDesc" = "Ідентифікатори чату адміністратора Telegram. (розділені комами) (отримайте тут @userinfobot) або (використовуйте команду '/id' у боті)" "telegramNotifyTime" = "Час сповіщення" @@ -483,8 +485,12 @@ "status" = "✅ Бот в порядку!" "usage" = "❗ Введіть текст для пошуку!" "getID" = "🆔 Ваш ідентифікатор: {{ .ID }}" -"helpAdminCommands" = "Для пошуку електронної пошти клієнта:\r\n/usage [Електронна пошта]\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n/inbound [Примітка]\r\n\r\nID чату Telegram:\r\n/id" +"helpAdminCommands" = "Для перезапуску Xray Core:\r\n/restart force\r\n\r\nДля пошуку електронної пошти клієнта:\r\n/usage [Електронна пошта]\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n/inbound [Примітка]\r\n\r\nID чату Telegram:\r\n/id" "helpClientCommands" = "Для пошуку статистики використовуйте наступну команду:\r\n/usage [Електронна пошта]\r\n\r\nID чату Telegram:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Операція успішна!" +"restartFailed" = "❗ Помилка в операції.\r\n\r\nПомилка: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core не запущений." [tgbot.messages] "cpuThreshold" = "🔴 Навантаження ЦП {{ .Percent }}% перевищує порогове значення {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }}: Успішно вимкнено." "askToAddUserId" = "Вашу конфігурацію не знайдено!\r\nБудь ласка, попросіть свого адміністратора використовувати ваш ідентифікатор Telegram у вашій конфігурації.\r\n\r\nВаш ідентифікатор користувача: {{ .TgUserID }}" "chooseClient" = "Виберіть клієнта для Вхідного {{ .Inbound }}" -"chooseInbound" = "Виберіть Вхідний" \ No newline at end of file +"chooseInbound" = "Виберіть Вхідний" diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index 2e082ead..bb5c00f8 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "Bạn phải nhận token từ quản lý bot Telegram @botfather" "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." +"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" "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" @@ -483,8 +485,12 @@ "status" = "✅ Bot hoạt động bình thường!" "usage" = "❗ Vui lòng cung cấp văn bản để tìm kiếm!" "getID" = "🆔 ID của bạn: {{ .ID }}" -"helpAdminCommands" = "Để tìm kiếm email của khách hàng:\r\n/usage [Email]\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/inbound [Ghi chú]\r\n\r\nID Trò chuyện Telegram:\r\n/id" +"helpAdminCommands" = "Để khởi động lại Xray Core:\r\n/restart force\r\n\r\nĐể tìm kiếm email của khách hàng:\r\n/usage [Email]\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/inbound [Ghi chú]\r\n\r\nID Trò chuyện Telegram:\r\n/id" "helpClientCommands" = "Để tìm kiếm thống kê, sử dụng lệnh sau:\r\n/usage [Email]\r\n\r\nID Trò chuyện Telegram:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ Hoạt động thành công!" +"restartFailed" = "❗ Lỗi trong quá trình hoạt động.\r\n\r\nLỗi: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core không chạy." [tgbot.messages] "cpuThreshold" = "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }} : Đã Tắt Thành Công." "askToAddUserId" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nID người dùng của bạn: {{ .TgUserID }}" "chooseClient" = "Chọn một Khách hàng cho Inbound {{ .Inbound }}" -"chooseInbound" = "Chọn một Inbound" \ No newline at end of file +"chooseInbound" = "Chọn một Inbound" diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml index d271b6b4..35062b30 100644 --- a/web/translation/translate.zh_CN.toml +++ b/web/translation/translate.zh_CN.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "从 '@BotFather' 获取的 Telegram 机器人令牌" "telegramProxy" = "SOCKS5 Proxy" "telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram(根据指南调整设置)" +"telegramAPIServer" = "Telegram API Server" +"telegramAPIServerDesc" = "要使用的 Telegram API 服务器。留空以使用默认服务器。" "telegramChatId" = "管理员聊天 ID" "telegramChatIdDesc" = "Telegram 管理员聊天 ID (多个以逗号分隔)(可通过 @userinfobot 获取,或在机器人中使用 '/id' 命令获取)" "telegramNotifyTime" = "通知时间" @@ -483,8 +485,12 @@ "status" = "✅ 机器人正常运行!" "usage" = "❗ 请输入要搜索的文本!" "getID" = "🆔 您的 ID 为:{{ .ID }}" -"helpAdminCommands" = "要搜索客户电子邮件:\r\n/usage [电子邮件]\r\n\r\n要搜索入站(带有客户统计数据):\r\n/inbound [备注]\r\n\r\nTelegram聊天ID:\r\n/id" +"helpAdminCommands" = "要重新启动 Xray Core:\r\n/restart force\r\n\r\n要搜索客户电子邮件:\r\n/usage [电子邮件]\r\n\r\n要搜索入站(带有客户统计数据):\r\n/inbound [备注]\r\n\r\nTelegram聊天ID:\r\n/id" "helpClientCommands" = "要搜索统计数据,请使用以下命令:\r\n/usage [电子邮件]\r\n\r\nTelegram聊天ID:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ 操作成功!" +"restartFailed" = "❗ 操作错误。\r\n\r\n错误: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core 未运行。" [tgbot.messages] "cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }}:已成功禁用。" "askToAddUserId" = "未找到您的配置!\r\n请向管理员询问,在您的配置中使用您的 Telegram 用户 ChatID。\r\n\r\n您的用户 ChatID:{{ .TgUserID }}" "chooseClient" = "为入站 {{ .Inbound }} 选择一个客户" -"chooseInbound" = "选择一个入站" \ No newline at end of file +"chooseInbound" = "选择一个入站" diff --git a/web/translation/translate.zh_TW.toml b/web/translation/translate.zh_TW.toml index 93478845..a7382769 100644 --- a/web/translation/translate.zh_TW.toml +++ b/web/translation/translate.zh_TW.toml @@ -265,6 +265,8 @@ "telegramTokenDesc" = "從 '@BotFather' 獲取的 Telegram 機器人令牌" "telegramProxy" = "SOCKS5 Proxy" "telegramProxyDesc" = "啟用 SOCKS5 代理連線到 Telegram(根據指南調整設定)" +"telegramAPIServer" = "Telegram API Server" +"telegramAPIServerDesc" = "要使用的 Telegram API 伺服器。留空以使用預設伺服器。" "telegramChatId" = "管理員聊天 ID" "telegramChatIdDesc" = "Telegram 管理員聊天 ID (多個以逗號分隔)(可通過 @userinfobot 獲取,或在機器人中使用 '/id' 命令獲取)" "telegramNotifyTime" = "通知時間" @@ -483,8 +485,12 @@ "status" = "✅ 機器人正常執行!" "usage" = "❗ 請輸入要搜尋的文字!" "getID" = "🆔 您的 ID 為:{{ .ID }}" -"helpAdminCommands" = "要搜尋客戶電子郵件:\r\n/usage [電子郵件]\r\n\r\n要搜尋入站(帶有客戶統計資料):\r\n/inbound [備註]\r\n\r\nTelegram聊天ID:\r\n/id" +"helpAdminCommands" = "要重新啟動 Xray Core:\r\n/restart force\r\n\r\n要搜尋客戶電子郵件:\r\n/usage [電子郵件]\r\n\r\n要搜尋入站(帶有客戶統計資料):\r\n/inbound [備註]\r\n\r\nTelegram聊天ID:\r\n/id" "helpClientCommands" = "要搜尋統計資料,請使用以下命令:\r\n/usage [電子郵件]\r\n\r\nTelegram聊天ID:\r\n/id" +"restartUsage" = "\r\n\r\n/restart force" +"restartSuccess" = "✅ 操作成功!" +"restartFailed" = "❗ 操作錯誤。\r\n\r\n錯誤: {{ .Error }}." +"xrayNotRunning" = "❗ Xray Core 未運行。" [tgbot.messages] "cpuThreshold" = "🔴 CPU 使用率為 {{ .Percent }}%,超過閾值 {{ .Threshold }}%" @@ -588,4 +594,4 @@ "disableSuccess" = "✅ {{ .Email }}:已成功禁用。" "askToAddUserId" = "未找到您的配置!\r\n請向管理員詢問,在您的配置中使用您的 Telegram 使用者 ChatID。\r\n\r\n您的使用者 ChatID:{{ .TgUserID }}" "chooseClient" = "為入站 {{ .Inbound }} 選擇一個客戶" -"chooseInbound" = "選擇一個入站" \ No newline at end of file +"chooseInbound" = "選擇一個入站" diff --git a/x-ui.sh b/x-ui.sh index 0b8602ed..e881b20f 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -416,10 +416,31 @@ disable() { } show_log() { - journalctl -u x-ui.service -e --no-pager -f - if [[ $# == 0 ]]; then + echo -e "${green}\t1.${plain} Debug Log" + 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 - fi + fi + ;; + 2) + sudo journalctl --rotate + sudo journalctl --vacuum-time=1s + echo "All Logs cleared." + restart + ;; + *) + echo "Invalid choice" + ;; + esac } show_banlog() { @@ -1449,7 +1470,7 @@ show_menu() { ${green}12.${plain} Stop ${green}13.${plain} Restart ${green}14.${plain} Check Status - ${green}15.${plain} Check Logs + ${green}15.${plain} Logs Management ———————————————— ${green}16.${plain} Enable Autostart ${green}17.${plain} Disable Autostart