diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js
index 392c5fa7..c8b2863d 100644
--- a/web/assets/js/model/inbound.js
+++ b/web/assets/js/model/inbound.js
@@ -1637,6 +1637,7 @@ class TcpMask extends XrayCommonClass {
class QuicParams extends XrayCommonClass {
constructor({
congestion = '',
+ bbrProfile = '',
debug = false,
brutalUp = 0,
brutalDown = 0,
@@ -1657,6 +1658,7 @@ class QuicParams extends XrayCommonClass {
} = {}) {
super();
this.congestion = congestion;
+ this.bbrProfile = bbrProfile;
this.debug = debug;
this.brutalUp = brutalUp;
this.brutalDown = brutalDown;
@@ -1678,7 +1680,7 @@ class QuicParams extends XrayCommonClass {
static hasAnyMeaningfulValue(json) {
if (!json || typeof json !== 'object') return false;
- const keys = ['congestion', 'debug', 'brutalUp', 'brutalDown', 'udpHop',
+ const keys = ['congestion', 'bbrProfile', 'debug', 'brutalUp', 'brutalDown', 'udpHop',
'initStreamReceiveWindow', 'maxStreamReceiveWindow',
'initConnectionReceiveWindow', 'maxConnectionReceiveWindow',
'maxIdleTimeout', 'keepAlivePeriod', 'disablePathMTUDiscovery',
@@ -1702,6 +1704,7 @@ class QuicParams extends XrayCommonClass {
const udpHop = json.udpHop || {};
return new QuicParams({
congestion: json.congestion || '',
+ bbrProfile: json.bbrProfile || '',
debug: !!json.debug,
brutalUp: this.getMbpsInt(json.brutalUp),
brutalDown: this.getMbpsInt(json.brutalDown),
@@ -1725,6 +1728,7 @@ class QuicParams extends XrayCommonClass {
toJson() {
const result = {};
if (this.congestion) result.congestion = this.congestion;
+ if (this.bbrProfile) result.bbrProfile = this.bbrProfile;
if (this.debug) result.debug = this.debug;
if (this.brutalUp) result.brutalUp = QuicParams.getMbpsStr(this.brutalUp);
if (this.brutalDown) result.brutalDown = QuicParams.getMbpsStr(this.brutalDown);
diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js
index 597a4e9d..2b263b09 100644
--- a/web/assets/js/model/outbound.js
+++ b/web/assets/js/model/outbound.js
@@ -1153,6 +1153,7 @@ class TcpMask extends CommonClass {
class QuicParams extends CommonClass {
constructor({
congestion = '',
+ bbrProfile = '',
debug = false,
brutalUp = 0,
brutalDown = 0,
@@ -1171,6 +1172,7 @@ class QuicParams extends CommonClass {
} = {}) {
super();
this.congestion = congestion;
+ this.bbrProfile = bbrProfile;
this.debug = debug;
this.brutalUp = brutalUp;
this.brutalDown = brutalDown;
@@ -1190,7 +1192,7 @@ class QuicParams extends CommonClass {
static hasAnyMeaningfulValue(json) {
if (!json || typeof json !== 'object') return false;
- const keys = ['congestion', 'debug', 'brutalUp', 'brutalDown',
+ const keys = ['congestion', 'bbrProfile', 'debug', 'brutalUp', 'brutalDown',
'initStreamReceiveWindow', 'maxStreamReceiveWindow',
'initConnectionReceiveWindow', 'maxConnectionReceiveWindow',
'maxIdleTimeout', 'keepAlivePeriod', 'disablePathMTUDiscovery',
@@ -1213,6 +1215,7 @@ class QuicParams extends CommonClass {
static fromJson(json = {}) {
return new QuicParams({
congestion: json.congestion || '',
+ bbrProfile: json.bbrProfile || '',
debug: !!json.debug,
brutalUp: QuicParams.getMbpsInt(json.brutalUp),
brutalDown: QuicParams.getMbpsInt(json.brutalDown),
@@ -1249,6 +1252,7 @@ class QuicParams extends CommonClass {
toJson() {
const result = {};
if (this.congestion) result.congestion = this.congestion;
+ if (this.bbrProfile) result.bbrProfile = this.bbrProfile;
if (this.debug) result.debug = this.debug;
if (this.brutalUp) result.brutalUp = QuicParams.getMbpsStr(this.brutalUp);
if (this.brutalDown) result.brutalDown = QuicParams.getMbpsStr(this.brutalDown);
diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html
index b4fea5a8..a78000c4 100644
--- a/web/html/xui/form/outbound.html
+++ b/web/html/xui/form/outbound.html
@@ -1076,6 +1076,21 @@
force-brutal
+
+
+
+
+ {{ i18n "pages.inbounds.stream.finalmask.bbrProfileDesc" }}
+
+ {{ i18n "pages.inbounds.stream.finalmask.bbrProfile" }}
+
+
+
+ standard
+ conservative
+ aggressive
+
+
diff --git a/web/html/xui/form/stream/stream_finalmask.html b/web/html/xui/form/stream/stream_finalmask.html
index ccf1a4c7..edaedaf5 100644
--- a/web/html/xui/form/stream/stream_finalmask.html
+++ b/web/html/xui/form/stream/stream_finalmask.html
@@ -288,6 +288,21 @@
force-brutal
+
+
+
+
+ {{ i18n "pages.inbounds.stream.finalmask.bbrProfileDesc" }}
+
+ {{ i18n "pages.inbounds.stream.finalmask.bbrProfile" }}
+
+
+
+ standard
+ conservative
+ aggressive
+
+
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index 3fba75ca..0c9227e7 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -476,6 +476,8 @@
"xmcProfilesDesc" = "Signed Minecraft profiles; both ends need the same list, and the client logs in with a random one. Enter a username and fetch the rest from Mojang"
"xmcFetch" = "Fetch"
"xmcHostnameDesc" = "The server address the client puts in its Minecraft handshake; empty uses the real one"
+"bbrProfile" = "BBR Profile"
+"bbrProfileDesc" = "Preset for BBR, used whenever BBR controls congestion: with bbr, with brutal when it falls back to BBR, and by default on XHTTP/3"
[pages.inbounds.stream.hysteria]
"authPassword" = "Auth Password"
diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml
index b52483c3..4ab91c5e 100644
--- a/web/translation/translate.fa_IR.toml
+++ b/web/translation/translate.fa_IR.toml
@@ -476,6 +476,8 @@
"xmcProfilesDesc" = "پروفایلهای امضاشده Minecraft؛ هر دو طرف باید لیست یکسان داشته باشند و کلاینت با یکی از آنها بهصورت تصادفی وارد میشود. نام کاربری را وارد کنید و بقیه را از Mojang بگیرید"
"xmcFetch" = "دریافت"
"xmcHostnameDesc" = "آدرس سروری که کلاینت در handshake ماینکرافت میفرستد؛ خالی یعنی آدرس واقعی"
+"bbrProfile" = "پروفایل BBR"
+"bbrProfileDesc" = "پیشتنظیم BBR که هر جا BBR کنترل ازدحام را بر عهده دارد استفاده میشود: با bbr، با brutal وقتی به BBR برمیگردد، و بهصورت پیشفرض در XHTTP/3"
[pages.inbounds.stream.hysteria]
"authPassword" = "رمز احراز هویت"
diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml
index 396e2e87..681c0a10 100644
--- a/web/translation/translate.ru_RU.toml
+++ b/web/translation/translate.ru_RU.toml
@@ -476,6 +476,8 @@
"xmcProfilesDesc" = "Подписанные профили Minecraft; у обеих сторон должен быть одинаковый список, клиент входит со случайным из них. Введите имя пользователя и получите остальное у Mojang"
"xmcFetch" = "Получить"
"xmcHostnameDesc" = "Адрес сервера, который клиент указывает в рукопожатии Minecraft; пусто — реальный адрес"
+"bbrProfile" = "Профиль BBR"
+"bbrProfileDesc" = "Пресет BBR, применяется всякий раз, когда перегрузкой управляет BBR: с bbr, с brutal при откате на BBR и по умолчанию в XHTTP/3"
[pages.inbounds.stream.hysteria]
"authPassword" = "Пароль аутентификации"
diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml
index 071bc7ed..04b75550 100644
--- a/web/translation/translate.vi_VN.toml
+++ b/web/translation/translate.vi_VN.toml
@@ -476,6 +476,8 @@
"xmcProfilesDesc" = "Hồ sơ Minecraft đã ký; hai đầu cần cùng danh sách, client đăng nhập bằng một hồ sơ ngẫu nhiên. Nhập tên người dùng và lấy phần còn lại từ Mojang"
"xmcFetch" = "Lấy"
"xmcHostnameDesc" = "Địa chỉ máy chủ client gửi trong handshake Minecraft; để trống dùng địa chỉ thật"
+"bbrProfile" = "Hồ sơ BBR"
+"bbrProfileDesc" = "Cấu hình sẵn cho BBR, dùng khi BBR điều khiển tắc nghẽn: với bbr, với brutal khi quay về BBR, và mặc định trên XHTTP/3"
[pages.inbounds.stream.hysteria]
"authPassword" = "Mật khẩu xác thực"
diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml
index c4ad6e80..0b0dfa08 100644
--- a/web/translation/translate.zh_Hans.toml
+++ b/web/translation/translate.zh_Hans.toml
@@ -476,6 +476,8 @@
"xmcProfilesDesc" = "已签名的 Minecraft 档案;两端需要相同的列表,客户端随机选用其一登录。输入用户名即可从 Mojang 获取其余信息"
"xmcFetch" = "获取"
"xmcHostnameDesc" = "客户端在 Minecraft 握手中填写的服务器地址;留空则使用真实地址"
+"bbrProfile" = "BBR 配置"
+"bbrProfileDesc" = "BBR 预设,在由 BBR 控制拥塞时生效:选择 bbr 时、brutal 回退到 BBR 时,以及 XHTTP/3 默认情况下"
[pages.inbounds.stream.hysteria]
"authPassword" = "认证密码"