diff options
Diffstat (limited to 'web')
| -rw-r--r-- | web/assets/js/model/setting.js | 3 | ||||
| -rw-r--r-- | web/assets/js/subscription.js | 7 | ||||
| -rw-r--r-- | web/entity/entity.go | 10 | ||||
| -rw-r--r-- | web/html/settings.html | 4 | ||||
| -rw-r--r-- | web/html/settings/panel/subscription/general.html | 86 | ||||
| -rw-r--r-- | web/html/settings/panel/subscription/json.html | 26 | ||||
| -rw-r--r-- | web/html/settings/panel/subscription/subpage.html | 17 | ||||
| -rw-r--r-- | web/service/setting.go | 39 |
8 files changed, 152 insertions, 40 deletions
diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js index af80a63e..d61d4b8e 100644 --- a/web/assets/js/model/setting.js +++ b/web/assets/js/model/setting.js @@ -38,6 +38,8 @@ class AllSetting { this.subPort = 2096; this.subPath = "/sub/"; this.subJsonPath = "/json/"; + this.subClashEnable = true; + this.subClashPath = "/clash/"; this.subDomain = ""; this.externalTrafficInformEnable = false; this.externalTrafficInformURI = ""; @@ -48,6 +50,7 @@ class AllSetting { this.subShowInfo = true; this.subURI = ""; this.subJsonURI = ""; + this.subClashURI = ""; this.subJsonFragment = ""; this.subJsonNoises = ""; this.subJsonMux = ""; diff --git a/web/assets/js/subscription.js b/web/assets/js/subscription.js index 228dcfa0..d08bfd28 100644 --- a/web/assets/js/subscription.js +++ b/web/assets/js/subscription.js @@ -9,6 +9,7 @@ sId: el.getAttribute('data-sid') || '', subUrl: el.getAttribute('data-sub-url') || '', subJsonUrl: el.getAttribute('data-subjson-url') || '', + subClashUrl: el.getAttribute('data-subclash-url') || '', download: el.getAttribute('data-download') || '', upload: el.getAttribute('data-upload') || '', used: el.getAttribute('data-used') || '', @@ -98,13 +99,19 @@ this.lang = LanguageManager.getLanguage(); const tpl = document.getElementById('subscription-data'); const sj = tpl ? tpl.getAttribute('data-subjson-url') : ''; + const sc = tpl ? tpl.getAttribute('data-subclash-url') : ''; if (sj) this.app.subJsonUrl = sj; + if (sc) this.app.subClashUrl = sc; drawQR(this.app.subUrl); try { const elJson = document.getElementById('qrcode-subjson'); if (elJson && this.app.subJsonUrl) { new QRious({ element: elJson, value: this.app.subJsonUrl, size: 220 }); } + const elClash = document.getElementById('qrcode-subclash'); + if (elClash && this.app.subClashUrl) { + new QRious({ element: elClash, value: this.app.subClashUrl, size: 220 }); + } } catch (e) { /* ignore */ } this._onResize = () => { this.viewportWidth = window.innerWidth; }; window.addEventListener('resize', this._onResize); diff --git a/web/entity/entity.go b/web/entity/entity.go index 40294925..14353cf0 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -76,6 +76,9 @@ type AllSetting struct { SubURI string `json:"subURI" form:"subURI"` // Subscription server URI SubJsonPath string `json:"subJsonPath" form:"subJsonPath"` // Path for JSON subscription endpoint SubJsonURI string `json:"subJsonURI" form:"subJsonURI"` // JSON subscription server URI + SubClashEnable bool `json:"subClashEnable" form:"subClashEnable"` // Enable Clash/Mihomo subscription endpoint + SubClashPath string `json:"subClashPath" form:"subClashPath"` // Path for Clash/Mihomo subscription endpoint + SubClashURI string `json:"subClashURI" form:"subClashURI"` // Clash/Mihomo subscription server URI SubJsonFragment string `json:"subJsonFragment" form:"subJsonFragment"` // JSON subscription fragment configuration SubJsonNoises string `json:"subJsonNoises" form:"subJsonNoises"` // JSON subscription noise configuration SubJsonMux string `json:"subJsonMux" form:"subJsonMux"` // JSON subscription mux configuration @@ -168,6 +171,13 @@ func (s *AllSetting) CheckValid() error { s.SubJsonPath += "/" } + if !strings.HasPrefix(s.SubClashPath, "/") { + s.SubClashPath = "/" + s.SubClashPath + } + if !strings.HasSuffix(s.SubClashPath, "/") { + s.SubClashPath += "/" + } + _, err := time.LoadLocation(s.TimeLocation) if err != nil { return common.NewError("time location not exist:", s.TimeLocation) diff --git a/web/html/settings.html b/web/html/settings.html index 48aad524..441e62de 100644 --- a/web/html/settings.html +++ b/web/html/settings.html @@ -79,10 +79,10 @@ </template> {{ template "settings/panel/subscription/general" . }} </a-tab-pane> - <a-tab-pane key="5" v-if="allSetting.subJsonEnable" :style="{ paddingTop: '20px' }"> + <a-tab-pane key="5" v-if="allSetting.subJsonEnable || allSetting.subClashEnable" :style="{ paddingTop: '20px' }"> <template #tab> <a-icon type="code"></a-icon> - <span>{{ i18n "pages.settings.subSettings" }} (JSON)</span> + <span>{{ i18n "pages.settings.subSettings" }} (Formats)</span> </template> {{ template "settings/panel/subscription/json" . }} </a-tab-pane> diff --git a/web/html/settings/panel/subscription/general.html b/web/html/settings/panel/subscription/general.html index 5d83aa37..725a9359 100644 --- a/web/html/settings/panel/subscription/general.html +++ b/web/html/settings/panel/subscription/general.html @@ -3,43 +3,58 @@ <a-collapse-panel key="1" header='{{ i18n "pages.xray.generalConfigs"}}'> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subEnable"}}</template> - <template #description>{{ i18n "pages.settings.subEnableDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subEnableDesc"}}</template> <template #control> <a-switch v-model="allSetting.subEnable"></a-switch> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>JSON Subscription</template> - <template #description>{{ i18n "pages.settings.subJsonEnable"}}</template> + <template #description>{{ i18n + "pages.settings.subJsonEnable"}}</template> <template #control> <a-switch v-model="allSetting.subJsonEnable"></a-switch> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> + <template #title>Clash / Mihomo Subscription</template> + <template #description>Enable direct Clash and Mihomo YAML + subscriptions.</template> + <template #control> + <a-switch v-model="allSetting.subClashEnable"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subListen"}}</template> - <template #description>{{ i18n "pages.settings.subListenDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subListenDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subListen"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subDomain"}}</template> - <template #description>{{ i18n "pages.settings.subDomainDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subDomainDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subDomain"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subPort"}}</template> - <template #description>{{ i18n "pages.settings.subPortDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subPortDesc"}}</template> <template #control> - <a-input-number v-model="allSetting.subPort" :min="1" :min="65535" + <a-input-number v-model="allSetting.subPort" :min="1" + :min="65535" :style="{ width: '100%' }"></a-input-number> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subPath"}}</template> - <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subPathDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subPath" @input="allSetting.subPath = ((typeof $event === 'string' ? $event : ($event && $event.target ? $event.target.value : '')) || '').replace(/[:*]/g, '')" @@ -49,9 +64,11 @@ </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subURI"}}</template> - <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subURIDesc"}}</template> <template #control> - <a-input type="text" placeholder="(http|https)://domain[:port]/path/" + <a-input type="text" + placeholder="(http|https)://domain[:port]/path/" v-model="allSetting.subURI"></a-input> </template> </a-setting-list-item> @@ -59,14 +76,16 @@ <a-collapse-panel key="2" header='{{ i18n "pages.settings.information" }}'> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subEncrypt"}}</template> - <template #description>{{ i18n "pages.settings.subEncryptDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subEncryptDesc"}}</template> <template #control> <a-switch v-model="allSetting.subEncrypt"></a-switch> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subShowInfo"}}</template> - <template #description>{{ i18n "pages.settings.subShowInfoDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subShowInfoDesc"}}</template> <template #control> <a-switch v-model="allSetting.subShowInfo"></a-switch> </template> @@ -74,59 +93,72 @@ <a-divider>{{ i18n "pages.xray.basicTemplate"}}</a-divider> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subTitle"}}</template> - <template #description>{{ i18n "pages.settings.subTitleDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subTitleDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subTitle"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subSupportUrl"}}</template> - <template #description>{{ i18n "pages.settings.subSupportUrlDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subSupportUrlDesc"}}</template> <template #control> - <a-input type="text" v-model="allSetting.subSupportUrl" placeholder="https://example.com"></a-input> + <a-input type="text" v-model="allSetting.subSupportUrl" + placeholder="https://example.com"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subProfileUrl"}}</template> - <template #description>{{ i18n "pages.settings.subProfileUrlDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subProfileUrlDesc"}}</template> <template #control> - <a-input type="text" v-model="allSetting.subProfileUrl" placeholder="https://example.com"></a-input> + <a-input type="text" v-model="allSetting.subProfileUrl" + placeholder="https://example.com"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subAnnounce"}}</template> - <template #description>{{ i18n "pages.settings.subAnnounceDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subAnnounceDesc"}}</template> <template #control> <a-textarea v-model="allSetting.subAnnounce"></a-textarea> </template> </a-setting-list-item> <a-divider>{{ i18n "pages.xray.advancedTemplate"}} (Happ)</a-divider> <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subEnableRouting"}}</template> - <template #description>{{ i18n "pages.settings.subEnableRoutingDesc"}}</template> + <template #title>{{ i18n + "pages.settings.subEnableRouting"}}</template> + <template #description>{{ i18n + "pages.settings.subEnableRoutingDesc"}}</template> <template #control> <a-switch v-model="allSetting.subEnableRouting"></a-switch> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subRoutingRules"}}</template> - <template #description>{{ i18n "pages.settings.subRoutingRulesDesc"}}</template> + <template #title>{{ i18n + "pages.settings.subRoutingRules"}}</template> + <template #description>{{ i18n + "pages.settings.subRoutingRulesDesc"}}</template> <template #control> - <a-textarea v-model="allSetting.subRoutingRules" placeholder="happ://routing/add/..."></a-textarea> + <a-textarea v-model="allSetting.subRoutingRules" + placeholder="happ://routing/add/..."></a-textarea> </template> </a-setting-list-item> </a-collapse-panel> <a-collapse-panel key="3" header='{{ i18n "pages.settings.certs" }}'> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subCertPath"}}</template> - <template #description>{{ i18n "pages.settings.subCertPathDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subCertPathDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subCertFile"></a-input> </template> </a-setting-list-item> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subKeyPath"}}</template> - <template #description>{{ i18n "pages.settings.subKeyPathDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subKeyPathDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subKeyFile"></a-input> </template> @@ -135,9 +167,11 @@ <a-collapse-panel key="4" header='{{ i18n "pages.settings.intervals"}}'> <a-setting-list-item paddings="small"> <template #title>{{ i18n "pages.settings.subUpdates"}}</template> - <template #description>{{ i18n "pages.settings.subUpdatesDesc"}}</template> + <template #description>{{ i18n + "pages.settings.subUpdatesDesc"}}</template> <template #control> - <a-input-number :min="1" v-model="allSetting.subUpdates" :style="{ width: '100%' }"></a-input-number> + <a-input-number :min="1" v-model="allSetting.subUpdates" + :style="{ width: '100%' }"></a-input-number> </template> </a-setting-list-item> </a-collapse-panel> diff --git a/web/html/settings/panel/subscription/json.html b/web/html/settings/panel/subscription/json.html index e8642305..9b83571a 100644 --- a/web/html/settings/panel/subscription/json.html +++ b/web/html/settings/panel/subscription/json.html @@ -1,8 +1,8 @@ {{define "settings/panel/subscription/json"}} <a-collapse default-active-key="1"> <a-collapse-panel key="1" header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subPath"}}</template> + <a-setting-list-item paddings="small" v-if="allSetting.subJsonEnable"> + <template #title>{{ i18n "pages.settings.subPath"}} (JSON)</template> <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> <template #control> <a-input type="text" v-model="allSetting.subJsonPath" @@ -11,14 +11,32 @@ placeholder="/json/"></a-input> </template> </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subURI"}}</template> + <a-setting-list-item paddings="small" v-if="allSetting.subJsonEnable"> + <template #title>{{ i18n "pages.settings.subURI"}} (JSON)</template> <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> <template #control> <a-input type="text" placeholder="(http|https)://domain[:port]/path/" v-model="allSetting.subJsonURI"></a-input> </template> </a-setting-list-item> + <a-setting-list-item paddings="small" v-if="allSetting.subClashEnable"> + <template #title>{{ i18n "pages.settings.subPath"}} (Clash)</template> + <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subClashPath" + @input="allSetting.subClashPath = ((typeof $event === 'string' ? $event : ($event && $event.target ? $event.target.value : '')) || '').replace(/[:*]/g, '')" + @blur="allSetting.subClashPath = (p => { p = p || '/'; if (!p.startsWith('/')) p='/' + p; if (!p.endsWith('/')) p += '/'; return p.replace(/\/+/g,'/'); })(allSetting.subClashPath)" + placeholder="/clash/"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small" v-if="allSetting.subClashEnable"> + <template #title>{{ i18n "pages.settings.subURI"}} (Clash)</template> + <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> + <template #control> + <a-input type="text" placeholder="(http|https)://domain[:port]/path/" + v-model="allSetting.subClashURI"></a-input> + </template> + </a-setting-list-item> </a-collapse-panel> <a-collapse-panel key="2" header='{{ i18n "pages.settings.fragment"}}'> <a-setting-list-item paddings="small"> diff --git a/web/html/settings/panel/subscription/subpage.html b/web/html/settings/panel/subscription/subpage.html index 794c67c3..64c1224d 100644 --- a/web/html/settings/panel/subscription/subpage.html +++ b/web/html/settings/panel/subscription/subpage.html @@ -83,7 +83,7 @@ <a-form-item> <a-space direction="vertical" align="center"> <a-row type="flex" :gutter="[8,8]" justify="center" style="width:100%"> - <a-col :xs="24" :sm="app.subJsonUrl ? 12 : 24" style="text-align:center;"> + <a-col :xs="24" :sm="app.subJsonUrl || app.subClashUrl ? 12 : 24" style="text-align:center;"> <tr-qr-box class="qr-box"> <a-tag color="purple" class="qr-tag"> <span>{{ i18n @@ -112,6 +112,19 @@ </tr-qr-bg> </tr-qr-box> </a-col> + <a-col v-if="app.subClashUrl" :xs="24" :sm="12" style="text-align:center;"> + <tr-qr-box class="qr-box"> + <a-tag color="purple" class="qr-tag"> + <span>Clash / Mihomo</span> + </a-tag> + <tr-qr-bg class="qr-bg-sub"> + <tr-qr-bg-inner class="qr-bg-sub-inner"> + <canvas id="qrcode-subclash" class="qr-cv" title='{{ i18n "copy" }}' + @click="copy(app.subClashUrl)"></canvas> + </tr-qr-bg-inner> + </tr-qr-bg> + </tr-qr-box> + </a-col> </a-row> </a-space> </a-form-item> @@ -242,7 +255,7 @@ </a-layout> <!-- Bootstrap data for external JS --> -<template id="subscription-data" data-sid="{{ .sId }}" data-sub-url="{{ .subUrl }}" data-subjson-url="{{ .subJsonUrl }}" +<template id="subscription-data" data-sid="{{ .sId }}" data-sub-url="{{ .subUrl }}" data-subjson-url="{{ .subJsonUrl }}" data-subclash-url="{{ .subClashUrl }}" data-download="{{ .download }}" data-upload="{{ .upload }}" data-used="{{ .used }}" data-total="{{ .total }}" data-remained="{{ .remained }}" data-expire="{{ .expire }}" data-lastonline="{{ .lastOnline }}" data-downloadbyte="{{ .downloadByte }}" data-uploadbyte="{{ .uploadByte }}" data-totalbyte="{{ .totalByte }}" diff --git a/web/service/setting.go b/web/service/setting.go index 5c93e9fd..7027d466 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -71,6 +71,9 @@ var defaultValueMap = map[string]string{ "subURI": "", "subJsonPath": "/json/", "subJsonURI": "", + "subClashEnable": "true", + "subClashPath": "/clash/", + "subClashURI": "", "subJsonFragment": "", "subJsonNoises": "", "subJsonMux": "", @@ -555,6 +558,18 @@ func (s *SettingService) GetSubJsonURI() (string, error) { return s.getString("subJsonURI") } +func (s *SettingService) GetSubClashEnable() (bool, error) { + return s.getBool("subClashEnable") +} + +func (s *SettingService) GetSubClashPath() (string, error) { + return s.getString("subClashPath") +} + +func (s *SettingService) GetSubClashURI() (string, error) { + return s.getString("subClashURI") +} + func (s *SettingService) GetSubJsonFragment() (string, error) { return s.getString("subJsonFragment") } @@ -750,11 +765,13 @@ func (s *SettingService) GetDefaultSettings(host string) (any, error) { "defaultKey": func() (any, error) { return s.GetKeyFile() }, "tgBotEnable": func() (any, error) { return s.GetTgbotEnabled() }, "subEnable": func() (any, error) { return s.GetSubEnable() }, - "subJsonEnable": func() (any, error) { return s.GetSubJsonEnable() }, - "subTitle": func() (any, error) { return s.GetSubTitle() }, - "subURI": func() (any, error) { return s.GetSubURI() }, - "subJsonURI": func() (any, error) { return s.GetSubJsonURI() }, - "remarkModel": func() (any, error) { return s.GetRemarkModel() }, + "subJsonEnable": func() (any, error) { return s.GetSubJsonEnable() }, + "subClashEnable": func() (any, error) { return s.GetSubClashEnable() }, + "subTitle": func() (any, error) { return s.GetSubTitle() }, + "subURI": func() (any, error) { return s.GetSubURI() }, + "subJsonURI": func() (any, error) { return s.GetSubJsonURI() }, + "subClashURI": func() (any, error) { return s.GetSubClashURI() }, + "remarkModel": func() (any, error) { return s.GetRemarkModel() }, "datepicker": func() (any, error) { return s.GetDatepicker() }, "ipLimitEnable": func() (any, error) { return s.GetIpLimitEnable() }, } @@ -776,12 +793,19 @@ func (s *SettingService) GetDefaultSettings(host string) (any, error) { subJsonEnable = b } } - if (subEnable && result["subURI"].(string) == "") || (subJsonEnable && result["subJsonURI"].(string) == "") { + subClashEnable := false + if v, ok := result["subClashEnable"]; ok { + if b, ok2 := v.(bool); ok2 { + subClashEnable = b + } + } + if (subEnable && result["subURI"].(string) == "") || (subJsonEnable && result["subJsonURI"].(string) == "") || (subClashEnable && result["subClashURI"].(string) == "") { subURI := "" subTitle, _ := s.GetSubTitle() subPort, _ := s.GetSubPort() subPath, _ := s.GetSubPath() subJsonPath, _ := s.GetSubJsonPath() + subClashPath, _ := s.GetSubClashPath() subDomain, _ := s.GetSubDomain() subKeyFile, _ := s.GetSubKeyFile() subCertFile, _ := s.GetSubCertFile() @@ -811,6 +835,9 @@ func (s *SettingService) GetDefaultSettings(host string) (any, error) { if subJsonEnable && result["subJsonURI"].(string) == "" { result["subJsonURI"] = subURI + subJsonPath } + if subClashEnable && result["subClashURI"].(string) == "" { + result["subClashURI"] = subURI + subClashPath + } } return result, nil |
