Kaynağa Gözat

[sub] improve usage info in Remark

Co-Authored-By: Alireza Ahmadi <[email protected]>
MHSanaei 1 yıl önce
ebeveyn
işleme
38e1d0f94e

+ 5 - 2
sub/subController.go

@@ -3,12 +3,14 @@ package sub
 import (
 	"encoding/base64"
 	"strings"
+	"x-ui/web/service"
 
 	"github.com/gin-gonic/gin"
 )
 
 type SUBController struct {
-	subService SubService
+	subService     SubService
+	settingService service.SettingService
 }
 
 func NewSUBController(g *gin.RouterGroup) *SUBController {
@@ -24,9 +26,10 @@ func (a *SUBController) initRouter(g *gin.RouterGroup) {
 }
 
 func (a *SUBController) subs(c *gin.Context) {
+	subShowInfo, _ := a.settingService.GetSubShowInfo()
 	subId := c.Param("subid")
 	host := strings.Split(c.Request.Host, ":")[0]
-	subs, headers, err := a.subService.GetSubs(subId, host)
+	subs, headers, err := a.subService.GetSubs(subId, host, subShowInfo)
 	if err != nil || len(subs) == 0 {
 		c.String(400, "Error!")
 	} else {

+ 65 - 104
sub/subService.go

@@ -18,12 +18,14 @@ import (
 
 type SubService struct {
 	address        string
+	showInfo       bool
 	inboundService service.InboundService
 	settingServics service.SettingService
 }
 
-func (s *SubService) GetSubs(subId string, host string) ([]string, []string, error) {
+func (s *SubService) GetSubs(subId string, host string, showInfo bool) ([]string, []string, error) {
 	s.address = host
+	s.showInfo = showInfo
 	var result []string
 	var headers []string
 	var traffic xray.ClientTraffic
@@ -57,7 +59,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, []string, err
 		}
 		for _, client := range clients {
 			if client.Enable && client.SubID == subId {
-				link := s.getLink(inbound, client.Email, client.ExpiryTime)
+				link := s.getLink(inbound, client.Email)
 				result = append(result, link)
 				clientTraffics = append(clientTraffics, s.getClientTraffics(inbound.ClientStats, client.Email))
 			}
@@ -123,39 +125,26 @@ func (s *SubService) getFallbackMaster(dest string) (*model.Inbound, error) {
 	return inbound, nil
 }
 
-func (s *SubService) getLink(inbound *model.Inbound, email string, expiryTime int64) string {
+func (s *SubService) getLink(inbound *model.Inbound, email string) string {
 	switch inbound.Protocol {
 	case "vmess":
-		return s.genVmessLink(inbound, email, expiryTime)
+		return s.genVmessLink(inbound, email)
 	case "vless":
-		return s.genVlessLink(inbound, email, expiryTime)
+		return s.genVlessLink(inbound, email)
 	case "trojan":
-		return s.genTrojanLink(inbound, email, expiryTime)
+		return s.genTrojanLink(inbound, email)
 	case "shadowsocks":
-		return s.genShadowsocksLink(inbound, email, expiryTime)
+		return s.genShadowsocksLink(inbound, email)
 	}
 	return ""
 }
 
-func (s *SubService) genVmessLink(inbound *model.Inbound, email string, expiryTime int64) string {
+func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
 	if inbound.Protocol != model.VMess {
 		return ""
 	}
-
-	remainedTraffic := s.getRemainedTraffic(email)
-	expiryTimeString := getExpiryTime(expiryTime)
-	remark := ""
-	isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
-
-	if isTerminated {
-		remark = fmt.Sprintf("%s: %s⛔️", email, "Terminated")
-	} else {
-		remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
-	}
-
 	obj := map[string]interface{}{
 		"v":    "2",
-		"ps":   remark,
 		"add":  s.address,
 		"port": inbound.Port,
 		"type": "none",
@@ -254,7 +243,7 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string, expiryTi
 		links := ""
 		for index, d := range domains {
 			domain := d.(map[string]interface{})
-			obj["ps"] = remark + "-" + domain["remark"].(string)
+			obj["ps"] = s.genRemark(inbound, email, domain["remark"].(string))
 			obj["add"] = domain["domain"].(string)
 			if index > 0 {
 				links += "\n"
@@ -265,11 +254,13 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string, expiryTi
 		return links
 	}
 
+	obj["ps"] = s.genRemark(inbound, email, "")
+
 	jsonStr, _ := json.MarshalIndent(obj, "", "  ")
 	return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
 }
 
-func (s *SubService) genVlessLink(inbound *model.Inbound, email string, expiryTime int64) string {
+func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
 	address := s.address
 	if inbound.Protocol != model.VLESS {
 		return ""
@@ -462,22 +453,11 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string, expiryTi
 	// Set the new query values on the URL
 	url.RawQuery = q.Encode()
 
-	remainedTraffic := s.getRemainedTraffic(email)
-	expiryTimeString := getExpiryTime(expiryTime)
-	remark := ""
-	isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
-
-	if isTerminated {
-		remark = fmt.Sprintf("%s: %s⛔️", email, "Terminated")
-	} else {
-		remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
-	}
-
 	if len(domains) > 0 {
 		links := ""
 		for index, d := range domains {
 			domain := d.(map[string]interface{})
-			url.Fragment = remark + "-" + domain["remark"].(string)
+			url.Fragment = s.genRemark(inbound, email, domain["remark"].(string))
 			url.Host = fmt.Sprintf("%s:%d", domain["domain"].(string), port)
 			if index > 0 {
 				links += "\n"
@@ -486,11 +466,12 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string, expiryTi
 		}
 		return links
 	}
-	url.Fragment = remark
+
+	url.Fragment = s.genRemark(inbound, email, "")
 	return url.String()
 }
 
-func (s *SubService) genTrojanLink(inbound *model.Inbound, email string, expiryTime int64) string {
+func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string {
 	address := s.address
 	if inbound.Protocol != model.Trojan {
 		return ""
@@ -680,22 +661,11 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string, expiryT
 	// Set the new query values on the URL
 	url.RawQuery = q.Encode()
 
-	remainedTraffic := s.getRemainedTraffic(email)
-	expiryTimeString := getExpiryTime(expiryTime)
-	remark := ""
-	isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
-
-	if isTerminated {
-		remark = fmt.Sprintf("%s: %s⛔️", email, "Terminated")
-	} else {
-		remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
-	}
-
 	if len(domains) > 0 {
 		links := ""
 		for index, d := range domains {
 			domain := d.(map[string]interface{})
-			url.Fragment = remark + "-" + domain["remark"].(string)
+			url.Fragment = s.genRemark(inbound, email, domain["remark"].(string))
 			url.Host = fmt.Sprintf("%s:%d", domain["domain"].(string), port)
 			if index > 0 {
 				links += "\n"
@@ -705,11 +675,11 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string, expiryT
 		return links
 	}
 
-	url.Fragment = remark
+	url.Fragment = s.genRemark(inbound, email, "")
 	return url.String()
 }
 
-func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string, expiryTime int64) string {
+func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) string {
 	address := s.address
 	if inbound.Protocol != model.Shadowsocks {
 		return ""
@@ -788,20 +758,53 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string, ex
 
 	// Set the new query values on the URL
 	url.RawQuery = q.Encode()
+	url.Fragment = s.genRemark(inbound, email, "")
+	return url.String()
+}
 
-	remainedTraffic := s.getRemainedTraffic(email)
-	expiryTimeString := getExpiryTime(expiryTime)
-	remark := ""
-	isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
-
-	if isTerminated {
-		remark = fmt.Sprintf("%s: %s⛔️", clients[clientIndex].Email, "Terminated")
+func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string {
+	var remark []string
+	if len(email) > 0 {
+		if len(inbound.Remark) > 0 {
+			remark = append(remark, inbound.Remark)
+		}
+		remark = append(remark, email)
+		if len(extra) > 0 {
+			remark = append(remark, extra)
+		}
 	} else {
-		remark = fmt.Sprintf("%s: %s - %s", clients[clientIndex].Email, remainedTraffic, expiryTimeString)
+		return inbound.Remark
 	}
-	
-	url.Fragment = remark
-	return url.String()
+
+	if s.showInfo {
+		statsExist := false
+		var stats xray.ClientTraffic
+		for _, clientStat := range inbound.ClientStats {
+			if clientStat.Email == email {
+				stats = clientStat
+				statsExist = true
+				break
+			}
+		}
+
+		// Get remained days
+		if statsExist {
+			if !stats.Enable {
+				return fmt.Sprintf("⛔️N/A-%s", strings.Join(remark, "-"))
+			}
+			if vol := stats.Total - (stats.Up + stats.Down); vol > 0 {
+				remark = append(remark, fmt.Sprintf("%s%s", common.FormatTraffic(vol), "📊"))
+			}
+			now := time.Now().Unix()
+			switch exp := stats.ExpiryTime / 1000; {
+			case exp > 0:
+				remark = append(remark, fmt.Sprintf("%d%s⏳", (exp-now)/86400, "Days"))
+			case exp < 0:
+				remark = append(remark, fmt.Sprintf("%d%s⏳", exp/-86400, "Days"))
+			}
+		}
+	}
+	return strings.Join(remark, "-")
 }
 
 func searchKey(data interface{}, key string) (interface{}, bool) {
@@ -845,45 +848,3 @@ func searchHost(headers interface{}) string {
 
 	return ""
 }
-
-func getExpiryTime(expiryTime int64) string {
-	now := time.Now().Unix()
-	expiryString := ""
-
-	timeDifference := expiryTime/1000 - now
-	isTerminated := timeDifference/3600 <= 0
-
-	if expiryTime == 0 {
-		expiryString = "♾ ⏳"
-	} else if timeDifference > 172800 {
-		expiryString = fmt.Sprintf("%d %s⏳", timeDifference/86400, "Days")
-	} else if expiryTime < 0 {
-		expiryString = fmt.Sprintf("%d %s⏳", expiryTime/-86400000, "Days")
-	} else if isTerminated {
-		expiryString = fmt.Sprintf("%s⛔️", "Terminated")
-	} else {
-		expiryString = fmt.Sprintf("%d %s⏳", timeDifference/3600, "Hours")
-	}
-
-	return expiryString
-}
-
-func (s *SubService) getRemainedTraffic(email string) string {
-	traffic, err := s.inboundService.GetClientTrafficByEmail(email)
-	if err != nil {
-		logger.Warning(err)
-	}
-
-	remainedTraffic := ""
-	isTerminated := traffic.Total-(traffic.Up+traffic.Down) < 0
-
-	if traffic.Total == 0 {
-		remainedTraffic = "♾ 📊"
-	} else if isTerminated {
-		remainedTraffic = fmt.Sprintf("%s⛔️", "Terminated")
-	} else {
-		remainedTraffic = fmt.Sprintf("%s%s", common.FormatTraffic(traffic.Total-(traffic.Up+traffic.Down)), "📊")
-	}
-
-	return remainedTraffic
-}

+ 1 - 0
web/assets/js/model/models.js

@@ -194,6 +194,7 @@ class AllSetting {
         this.subCertFile = "";
         this.subKeyFile = "";
         this.subUpdates = 0;
+        this.subShowInfo = false;
 
         this.timeLocation = "Asia/Tehran";
 

+ 1 - 0
web/controller/setting.go

@@ -79,6 +79,7 @@ func (a *SettingController) getDefaultSettings(c *gin.Context) {
 		"subDomain":   func() (interface{}, error) { return a.settingService.GetSubDomain() },
 		"subKeyFile":  func() (interface{}, error) { return a.settingService.GetSubKeyFile() },
 		"subCertFile": func() (interface{}, error) { return a.settingService.GetSubCertFile() },
+		"subShowInfo": func() (interface{}, error) { return a.settingService.GetSubShowInfo() },
 	}
 
 	result := make(map[string]interface{})

+ 1 - 0
web/entity/entity.go

@@ -55,6 +55,7 @@ type AllSetting struct {
 	SubCertFile        string `json:"subCertFile" form:"subCertFile"`
 	SubKeyFile         string `json:"subKeyFile" form:"subKeyFile"`
 	SubUpdates         int    `json:"subUpdates" form:"subUpdates"`
+	SubShowInfo        bool   `json:"subShowInfo" form:"subShowInfo"`
 }
 
 func (s *AllSetting) CheckValid() error {

+ 1 - 0
web/html/xui/settings.html

@@ -406,6 +406,7 @@
                             </a-row>
                             <a-list item-layout="horizontal" :style="themeSwitcher.textStyle">
                                 <setting-list-item type="switch" title='{{ i18n "pages.settings.subEnable"}}' desc='{{ i18n "pages.settings.subEnableDesc"}}' v-model="allSetting.subEnable"></setting-list-item>
+                                <setting-list-item type="switch" title='{{ i18n "pages.settings.subShowInfo"}}' desc='{{ i18n "pages.settings.subShowInfoDesc"}}' v-model="allSetting.subShowInfo"></setting-list-item>
                                 <setting-list-item type="text" title='{{ i18n "pages.settings.subListen"}}' desc='{{ i18n "pages.settings.subListenDesc"}}' v-model="allSetting.subListen"></setting-list-item>
                                 <setting-list-item type="text" title='{{ i18n "pages.settings.subDomain"}}' desc='{{ i18n "pages.settings.subDomainDesc"}}' v-model="allSetting.subDomain"></setting-list-item>
                                 <setting-list-item type="number" title='{{ i18n "pages.settings.subPort"}}' desc='{{ i18n "pages.settings.subPortDesc"}}' v-model.number="allSetting.subPort"></setting-list-item>

+ 5 - 0
web/service/setting.go

@@ -51,6 +51,7 @@ var defaultValueMap = map[string]string{
 	"subCertFile":        "",
 	"subKeyFile":         "",
 	"subUpdates":         "12",
+	"subShowInfo":        "false",
 }
 
 type SettingService struct {
@@ -396,6 +397,10 @@ func (s *SettingService) GetSubUpdates() (int, error) {
 	return s.getInt("subUpdates")
 }
 
+func (s *SettingService) GetSubShowInfo() (bool, error) {
+	return s.getBool("subShowInfo")
+}
+
 func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
 	if err := allSetting.CheckValid(); err != nil {
 		return err

+ 2 - 0
web/translation/translate.en_US.toml

@@ -274,6 +274,8 @@
 "subDomainDesc" = "Leave blank by default to monitor all domains and IPs"
 "subUpdates" = "Subscription update intervals"
 "subUpdatesDesc" = "Interval hours between updates in client application"
+"subShowInfo" = "Show usage info"
+"subShowInfoDesc" = "Show remianed traffic and date after config name"
 
 [pages.settings.templates]
 "title" = "Templates"

+ 2 - 0
web/translation/translate.fa_IR.toml

@@ -274,6 +274,8 @@
 "subDomainDesc" = "برای نظارت بر همه دامنه ها و آی‌پی ها به طور پیش فرض خالی بگذارید"
 "subUpdates" = "فاصله به روز رسانی های سابسکریپشن"
 "subUpdatesDesc" = "ساعت های فاصله بین به روز رسانی در برنامه کاربر"
+"subShowInfo" = "نمایش اطلاعات مصرف"
+"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در هر کانفیگ نمایش میدهد"
 
 [pages.settings.templates]
 "title" = "الگوها"

+ 2 - 0
web/translation/translate.ru_RU.toml

@@ -274,6 +274,8 @@
 "subDomainDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все домены и IP-адреса"
 "subUpdates" = "Интервалы обновления подписки"
 "subUpdatesDesc" = "Часовой интервал между обновлениями в клиентском приложении"
+"subShowInfo" = "Показать информацию об использовании"
+"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
 
 [pages.settings.templates]
 "title" = "Шаблоны"

+ 2 - 0
web/translation/translate.vi_VN.toml

@@ -274,6 +274,8 @@
 "subDomainDesc" = "Mặc định để trống để nghe tất cả các tên miền và IP"
 "subUpdates" = "Khoảng thời gian cập nhật đăng ký"
 "subUpdatesDesc" = "Số giờ giữa các cập nhật trong ứng dụng khách"
+"subShowInfo" = "Hiển thị thông tin sử dụng"
+"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
 
 [pages.settings.templates]
 "title" = "Mẫu"

+ 2 - 0
web/translation/translate.zh_Hans.toml

@@ -274,6 +274,8 @@
 "subDomainDesc" = "留空默认监控所有域名和IP"
 "subUpdates" = "订阅更新间隔"
 "subUpdatesDesc" = "客户端应用程序更新之间的间隔时间"
+"subShowInfo" = "显示使用信息"
+"subShowInfoDesc" = "在配置名称后显示剩余流量和日期"
 
 [pages.settings.templates]
 "title" = "模板"