feat(sub): add dummy info node and status configs for subscriptions (#6412)

* feat(settings): add subInfoNodeEnable and status template settings

* feat(sub): add dummy info node and status configs for raw links

* feat(sub): support dummy info node in clash and json subscriptions

* feat(ui): add subscription info node switch and status templates to settings

* style: apply gofumpt formatting

* fix(sub): address review feedback on subscription info node

- Restore GetSubs contract to avoid unintended remark expansions on non-subscription-body calls.
- Exclude dummy info node from Clash PROXY select group when active server nodes exist.
- Track hasEnabledClient and set traffic.Enable in JSON and Clash paths so status tokens evaluate correctly.
- Deterministically sort client emails across subscriptions before selecting primaryEmail.
- Consolidate duplicated info-node evaluation logic into resolveInfoNodeRemark helper.
- Remove redundant pure-getter test from setting_sub_info_node_test.go.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
This commit is contained in:
Rouzbeh†
2026-09-08 18:44:01 +03:30
committed by GitHub
parent b8597314f8
commit 9f76a66dcf
33 changed files with 1374 additions and 35 deletions
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "الأسلوب المستخدم في طلبات probe.",
"note": "تحمل موزّعات leastPing/leastLoad دائمًا burstObservatory. يخصّص هذا المفتاح معاملات probe — أوقفه لاستخدام الإعدادات الافتراضية المدمجة. تُطبَّق التغييرات بعد إعادة تشغيل اللوحة."
}
}
},
"subInfoNodeEnable": "تكوين معلومات منفصل / عقدة وهمية",
"subInfoNodeEnableDesc": "عند التفعيل، يتم عرض الملاحظات وحركة المرور/الأيام المتبقية كتكوين SOCKS منفصل في الأعلى، وعند انتهاء الصلاحية أو نفاد البيانات يتم إرجاع تكوين الحالة فقط.",
"subExpiredTemplate": "قالب انتهاء الصلاحية",
"subExpiredTemplateDesc": "قالب التكوين الوهمي عند انتهاء صلاحية اشتراك المستخدم.",
"subTrafficDepletedTemplate": "قالب نفاد البيانات",
"subTrafficDepletedTemplateDesc": "قالب التكوين الوهمي عند استهلاك حصة بيانات المستخدم بالكامل."
},
"xray": {
"save": "احفظ",
+7 -1
View File
@@ -1574,7 +1574,13 @@
"httpMethodDesc": "Method used for probe requests.",
"note": "leastPing/leastLoad balancers always carry a burst observatory. This switch customises its probe parameters — turn it off to use the built-in defaults. Changes apply after a panel restart."
}
}
},
"subInfoNodeEnable": "Separate Info Config / Dummy Node",
"subInfoNodeEnableDesc": "When enabled, remarks and remaining traffic/days are served as a separate dummy SOCKS config at the top, and expired/depleted subscriptions return only the status config.",
"subExpiredTemplate": "Expired Template",
"subExpiredTemplateDesc": "Template for the dummy config when the subscriber account has expired.",
"subTrafficDepletedTemplate": "Traffic Depleted Template",
"subTrafficDepletedTemplateDesc": "Template for the dummy config when subscriber traffic quota is exhausted."
},
"xray": {
"save": "Save",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Método usado para las solicitudes de probe.",
"note": "Los balanceadores leastPing/leastLoad siempre llevan un burstObservatory. Este interruptor personaliza sus parámetros de probe — apágalo para usar los valores predeterminados integrados. Los cambios se aplican tras reiniciar el panel."
}
}
},
"subInfoNodeEnable": "Configuración de información separada / Nodo ficticio",
"subInfoNodeEnableDesc": "Si está activado, la información de tráfico y días restantes se muestra en un nodo SOCKS ficticio arriba, y las suscripciones caducadas o agotadas devuelven solo el estado.",
"subExpiredTemplate": "Plantilla de expirado",
"subExpiredTemplateDesc": "Plantilla para el nodo ficticio cuando la suscripción ha expirado.",
"subTrafficDepletedTemplate": "Plantilla de tráfico agotado",
"subTrafficDepletedTemplateDesc": "Plantilla para el nodo ficticio cuando el límite de tráfico se ha agotado."
},
"xray": {
"save": "Guardar configuración",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "متد استفاده‌شده برای درخواست‌های probe.",
"note": "موزان‌کننده‌های leastPing/leastLoad همیشه burstObservatory دارند. این کلید پارامترهای probe آن را سفارشی می‌کند — آن را خاموش کنید تا از پیش‌فرض‌های داخلی استفاده شود. تغییرات پس از راه‌اندازی مجدد پنل اعمال می‌شوند."
}
}
},
"subInfoNodeEnable": "کانفیگ جداگانه اطلاعات / نود نمایشی",
"subInfoNodeEnableDesc": "در صورت فعال بودن، مشخصات و حجم/روزهای باقیمانده به عنوان یک کانفیگ مجزای ساکس در بالای لیست نمایش داده می‌شود و در صورت انقضا یا اتمام حجم فقط پیام وضعیت ارسال می‌شود.",
"subExpiredTemplate": "قالب پیام انقضا",
"subExpiredTemplateDesc": "قالب کانفیگ نمایشی زمانی که اشتراک کاربر منقضی شده است.",
"subTrafficDepletedTemplate": "قالب پیام اتمام حجم",
"subTrafficDepletedTemplateDesc": "قالب کانفیگ نمایشی زمانی که حجم اشتراک کاربر به پایان رسیده است."
},
"xray": {
"save": "ذخیره",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Metode yang dipakai untuk permintaan probe.",
"note": "Penyeimbang leastPing/leastLoad selalu membawa burstObservatory. Sakelar ini menyesuaikan parameter probe-nya — matikan untuk memakai bawaan default. Perubahan berlaku setelah panel dimulai ulang."
}
}
},
"subInfoNodeEnable": "Konfigurasi Info Terpisah / Node Dummy",
"subInfoNodeEnableDesc": "Saat diaktifkan, catatan dan sisa kuota/hari disajikan sebagai konfigurasi SOCKS dummy terpisah di bagian atas, dan langganan kedaluwarsa/habis hanya mengembalikan status.",
"subExpiredTemplate": "Templat Kedaluwarsa",
"subExpiredTemplateDesc": "Templat untuk konfigurasi dummy saat akun langganan telah kedaluwarsa.",
"subTrafficDepletedTemplate": "Templat Kuota Habis",
"subTrafficDepletedTemplateDesc": "Templat untuk konfigurasi dummy saat kuota data langganan telah habis."
},
"xray": {
"save": "Simpan",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "プローブ要求に使う HTTP メソッド。",
"note": "leastPing/leastLoad バランサーは常に burstObservatory を持ちます。このスイッチはプローブパラメータをカスタマイズします — オフにすると組み込みのデフォルトを使います。変更はパネルの再起動後に反映されます。"
}
}
},
"subInfoNodeEnable": "個別情報設定 / ダミーノード",
"subInfoNodeEnableDesc": "有効にすると、備考と残りの通信量/日数が上部の独立したSOCKSダミー構成として表示され、期限切れや通信量超過時はステータスのみが返されます。",
"subExpiredTemplate": "期限切れテンプレート",
"subExpiredTemplateDesc": "サブスクリプションの有効期限が切れた際のダミー構成用テンプレート。",
"subTrafficDepletedTemplate": "通信量超過テンプレート",
"subTrafficDepletedTemplateDesc": "サブスクリプションの通信量が上限に達した際のダミー構成用テンプレート。"
},
"xray": {
"importRules": "ルールをインポート",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Método usado nas requisições de probe.",
"note": "Balanceadores leastPing/leastLoad sempre carregam um burstObservatory. Esta opção personaliza seus parâmetros de probe — desligue-a para usar os padrões integrados. As alterações se aplicam após reiniciar o painel."
}
}
},
"subInfoNodeEnable": "Configuração de informações separada / Nó fictício",
"subInfoNodeEnableDesc": "Quando ativado, observações e tráfego/dias restantes são exibidos em uma configuração SOCKS fictícia no topo, e assinaturas expiradas/esgotadas retornam apenas o status.",
"subExpiredTemplate": "Modelo expirado",
"subExpiredTemplateDesc": "Modelo para a configuração fictícia quando a assinatura expirou.",
"subTrafficDepletedTemplate": "Modelo de tráfego esgotado",
"subTrafficDepletedTemplateDesc": "Modelo para a configuração fictícia quando a cota de tráfego foi esgotada."
},
"xray": {
"importRules": "Importar regras",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Метод запросов при проверках.",
"note": "Балансировщики leastPing/leastLoad всегда содержат burst-обсерваторию. Этот переключатель настраивает её параметры проб — выключите, чтобы использовать встроенные значения по умолчанию. Изменения применяются после перезапуска панели."
}
}
},
"subInfoNodeEnable": "Отдельный инфо-конфиг / фиктивный узел",
"subInfoNodeEnableDesc": "Если включено, примечание и остаток трафика/дней отображаются отдельным SOCKS-конфигом вверху, а при истечении срока/трафика возвращается только статус.",
"subExpiredTemplate": "Шаблон истекшей подписки",
"subExpiredTemplateDesc": "Шаблон для фиктивного узла, когда срок действия подписки истек.",
"subTrafficDepletedTemplate": "Шаблон исчерпания трафика",
"subTrafficDepletedTemplateDesc": "Шаблон для фиктивного узла, когда лимит трафика исчерпан."
},
"xray": {
"importRules": "Импорт правил",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Probe isteklerinde kullanılan HTTP yöntemi.",
"note": "leastPing/leastLoad dengeleyicileri her zaman bir burstObservatory taşır. Bu anahtar probe parametrelerini özelleştirir — yerleşik varsayılanları kullanmak için kapatın. Değişiklikler panel yeniden başlatıldıktan sonra uygulanır."
}
}
},
"subInfoNodeEnable": "Ayrı Bilgi Yapılandırması / Sahte Düğüm",
"subInfoNodeEnableDesc": "Etkinleştirildiğinde, notlar ve kalan trafik/günler en üstte ayrı bir sahte SOCKS yapılandırması olarak sunulur; süresi dolmuş veya kotası bitmiş abonelikler yalnızca durum yapılandırmasını alır.",
"subExpiredTemplate": "Süresi Dolmuş Şablonu",
"subExpiredTemplateDesc": "Abonelik süresi dolduğunda sahte yapılandırma için kullanılacak şablon.",
"subTrafficDepletedTemplate": "Trafik Tükendi Şablonu",
"subTrafficDepletedTemplateDesc": "Abonelik trafik kotası bittiğinde sahte yapılandırma için kullanılacak şablon."
},
"xray": {
"save": "Kaydet",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Метод запитів під час перевірок.",
"note": "Балансувальники leastPing/leastLoad завжди мають burstObservatory. Цей перемикач налаштовує її параметри probe — вимкніть, щоб використовувати вбудовані значення за замовчуванням. Зміни застосовуються після перезапуску панелі."
}
}
},
"subInfoNodeEnable": "Окремий інфо-конфіг / фіктивний вузол",
"subInfoNodeEnableDesc": "Якщо увімкнено, примітка та залишок трафіку/днів відображаються окремим SOCKS-конфігом угорі, а після закінчення терміну/трафіку повертається лише статус.",
"subExpiredTemplate": "Шаблон закінчення терміну",
"subExpiredTemplateDesc": "Шаблон для фіктивного вузла, коли термін дії підписки закінчився.",
"subTrafficDepletedTemplate": "Шаблон вичерпання трафіку",
"subTrafficDepletedTemplateDesc": "Шаблон для фіктивного вузла, коли ліміт трафіку вичерпано."
},
"xray": {
"save": "Зберегти",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "Phương thức dùng cho yêu cầu probe.",
"note": "Các bộ cân bằng leastPing/leastLoad luôn mang một burstObservatory. Công tắc này tùy chỉnh các tham số probe — tắt nó để dùng mặc định tích hợp. Các thay đổi áp dụng sau khi khởi động lại bảng điều khiển."
}
}
},
"subInfoNodeEnable": "Cấu hình thông tin riêng / Nút ảo",
"subInfoNodeEnableDesc": "Khi bật, ghi chú và lưu lượng/ngày còn lại sẽ hiển thị dưới dạng cấu hình SOCKS ảo riêng ở trên cùng, và đăng ký hết hạn/hết dung lượng chỉ trả về cấu hình trạng thái.",
"subExpiredTemplate": "Mẫu hết hạn",
"subExpiredTemplateDesc": "Mẫu cho cấu hình ảo khi tài khoản đăng ký đã hết hạn.",
"subTrafficDepletedTemplate": "Mẫu hết dung lượng",
"subTrafficDepletedTemplateDesc": "Mẫu cho cấu hình ảo khi tài khoản đăng ký đã dùng hết dung lượng."
},
"xray": {
"importRules": "Nhập quy tắc",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "探活请求使用的 HTTP 方法。",
"note": "leastPing/leastLoad 均衡器始终带有 burstObservatory。此开关自定义其探活参数 — 关闭以使用内置默认值。更改在面板重启后生效。"
}
}
},
"subInfoNodeEnable": "独立信息配置 / 提示节点",
"subInfoNodeEnableDesc": "启用后,备注及剩余流量/天数将作为单独的 SOCKS 提示配置显示在顶部;过期或流量耗尽时仅返回状态提示。",
"subExpiredTemplate": "过期提示模板",
"subExpiredTemplateDesc": "用户订阅过期时提示配置的备注模板。",
"subTrafficDepletedTemplate": "流量耗尽模板",
"subTrafficDepletedTemplateDesc": "用户订阅流量用尽时提示配置的备注模板。"
},
"xray": {
"importRules": "导入规则",
+7 -1
View File
@@ -1456,7 +1456,13 @@
"httpMethodDesc": "探活請求使用的 HTTP 方法。",
"note": "leastPing/leastLoad 平衡器始終帶有 burstObservatory。此開關自訂其探活參數 — 關閉以使用內建預設值。變更在面板重啟後生效。"
}
}
},
"subInfoNodeEnable": "獨立資訊配置 / 提示節點",
"subInfoNodeEnableDesc": "啟用後,備註及剩餘流量/天數將作為單獨的 SOCKS 提示配置顯示在頂部;過期或流量耗盡時僅返回狀態提示。",
"subExpiredTemplate": "過期提示範本",
"subExpiredTemplateDesc": "使用者訂閱過期時提示配置的備註範本。",
"subTrafficDepletedTemplate": "流量耗盡範本",
"subTrafficDepletedTemplateDesc": "使用者訂閱流量用盡時提示配置的備註範本。"
},
"xray": {
"save": "儲存",