🐶 Sync 2025-11-02 14:26:26

This commit is contained in:
actions-user
2025-11-02 14:26:26 +08:00
parent 64bcc56c2a
commit ac011db799
1557 changed files with 746465 additions and 0 deletions

View File

@@ -0,0 +1 @@
!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(u){"use strict";function f(e,t){clearTimeout(t.timeout),u.off(window,"mouseup",t.hurry),u.off(window,"keyup",t.hurry)}u.defineOption("autoRefresh",!1,function(e,t){function o(){i.display.wrapper.offsetHeight?(f(0,r),i.display.lastWrapHeight!=i.display.wrapper.clientHeight&&i.refresh()):r.timeout=setTimeout(o,r.delay)}var i,r;e.state.autoRefresh&&(f(0,e.state.autoRefresh),e.state.autoRefresh=null),t&&0==e.display.wrapper.offsetHeight&&((r=(i=e).state.autoRefresh={delay:t.delay||250}).timeout=setTimeout(o,r.delay),r.hurry=function(){clearTimeout(r.timeout),r.timeout=setTimeout(o,50)},u.on(window,"mouseup",r.hurry),u.on(window,"keyup",r.hurry))})});

View File

@@ -0,0 +1 @@
.CodeMirror-lint-markers{width:16px}.CodeMirror-lint-tooltip{background-color:#ffd;border:1px solid #000;border-radius:4px 4px 4px 4px;color:#000;font-family:monospace;font-size:10pt;overflow:hidden;padding:2px 5px;position:fixed;white-space:pre;white-space:pre-wrap;z-index:100;max-width:600px;opacity:0;transition:opacity .4s;-moz-transition:opacity .4s;-webkit-transition:opacity .4s;-o-transition:opacity .4s;-ms-transition:opacity .4s}.CodeMirror-lint-mark{background-position:left bottom;background-repeat:repeat-x}.CodeMirror-lint-mark-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=)}.CodeMirror-lint-mark-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==)}.CodeMirror-lint-marker{background-position:center center;background-repeat:no-repeat;cursor:pointer;display:inline-block;height:16px;width:16px;vertical-align:middle;position:relative}.CodeMirror-lint-message{padding-left:18px;background-position:top left;background-repeat:no-repeat}.CodeMirror-lint-marker-warning,.CodeMirror-lint-message-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=)}.CodeMirror-lint-marker-error,.CodeMirror-lint-message-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=)}.CodeMirror-lint-marker-multiple{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:right bottom;width:100%;height:100%}.CodeMirror-lint-line-error{background-color:rgba(183,76,81,.08)}.CodeMirror-lint-line-warning{background-color:rgba(255,211,0,.1)}

View File

@@ -0,0 +1 @@
!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(p){"use strict";var h="CodeMirror-lint-markers",g="CodeMirror-lint-line-";function u(t){t.parentNode&&t.parentNode.removeChild(t)}function v(t,e,n,o){t=t,e=e,n=n,(i=document.createElement("div")).className="CodeMirror-lint-tooltip cm-s-"+t.options.theme,i.appendChild(n.cloneNode(!0)),(t.state.lint.options.selfContain?t.getWrapperElement():document.body).appendChild(i),p.on(document,"mousemove",a),a(e),null!=i.style.opacity&&(i.style.opacity=1);var i,r=i;function a(t){if(!i.parentNode)return p.off(document,"mousemove",a);var e=Math.max(0,t.clientY-i.offsetHeight-5),t=Math.max(0,Math.min(t.clientX+5,i.ownerDocument.defaultView.innerWidth-i.offsetWidth));i.style.top=e+"px",i.style.left=t+"px"}function l(){var t;p.off(o,"mouseout",l),r&&((t=r).parentNode&&(null==t.style.opacity&&u(t),t.style.opacity=0,setTimeout(function(){u(t)},600)),r=null)}var s=setInterval(function(){if(r)for(var t=o;;t=t.parentNode){if((t=t&&11==t.nodeType?t.host:t)==document.body)return;if(!t){l();break}}if(!r)return clearInterval(s)},400);p.on(o,"mouseout",l)}function a(s,t,e){for(var n in this.marked=[],(t=t instanceof Function?{getAnnotations:t}:t)&&!0!==t||(t={}),this.options={},this.linterOptions=t.options||{},o)this.options[n]=o[n];for(var n in t)o.hasOwnProperty(n)?null!=t[n]&&(this.options[n]=t[n]):t.options||(this.linterOptions[n]=t[n]);this.timeout=null,this.hasGutter=e,this.onMouseOver=function(t){var e=s,n=t.target||t.srcElement;if(/\bCodeMirror-lint-mark-/.test(n.className)){for(var n=n.getBoundingClientRect(),o=(n.left+n.right)/2,n=(n.top+n.bottom)/2,i=e.findMarksAt(e.coordsChar({left:o,top:n},"client")),r=[],a=0;a<i.length;++a){var l=i[a].__annotation;l&&r.push(l)}r.length&&!function(t,e,n){for(var o=n.target||n.srcElement,i=document.createDocumentFragment(),r=0;r<e.length;r++){var a=e[r];i.appendChild(M(a))}v(t,n,i,o)}(e,r,t)}},this.waitingFor=0}var o={highlightLines:!1,tooltips:!0,delay:500,lintOnChange:!0,getAnnotations:null,async:!1,selfContain:null,formatAnnotation:null,onUpdateLinting:null};function C(t){var n,e=t.state.lint;e.hasGutter&&t.clearGutter(h),e.options.highlightLines&&(n=t).eachLine(function(t){var e=t.wrapClass&&/\bCodeMirror-lint-line-\w+\b/.exec(t.wrapClass);e&&n.removeLineClass(t,"wrap",e[0])});for(var o=0;o<e.marked.length;++o)e.marked[o].clear();e.marked.length=0}function M(t){var e=(e=t.severity)||"error",n=document.createElement("div");return n.className="CodeMirror-lint-message CodeMirror-lint-message-"+e,void 0!==t.messageHTML?n.innerHTML=t.messageHTML:n.appendChild(document.createTextNode(t.message)),n}function l(e){var t,n,o,i,r,a,l=e.state.lint;function s(){a=-1,o.off("change",s)}!l||(t=(i=l.options).getAnnotations||e.getHelper(p.Pos(0,0),"lint"))&&(i.async||t.async?(i=t,r=(o=e).state.lint,a=++r.waitingFor,o.on("change",s),i(o.getValue(),function(t,e){o.off("change",s),r.waitingFor==a&&(e&&t instanceof p&&(t=e),o.operation(function(){c(o,t)}))},r.linterOptions,o)):(n=t(e.getValue(),l.linterOptions,e))&&(n.then?n.then(function(t){e.operation(function(){c(e,t)})}):e.operation(function(){c(e,n)})))}function c(t,e){var n=t.state.lint;if(n){for(var o,i,r=n.options,a=(C(t),function(t){for(var e=[],n=0;n<t.length;++n){var o=t[n],i=o.from.line;(e[i]||(e[i]=[])).push(o)}return e}(e)),l=0;l<a.length;++l){var s=a[l];if(s){for(var u=null,c=n.hasGutter&&document.createDocumentFragment(),f=0;f<s.length;++f){var m=s[f],d=m.severity;i=d=d||"error",u="error"==(o=u)?o:i,r.formatAnnotation&&(m=r.formatAnnotation(m)),n.hasGutter&&c.appendChild(M(m)),m.to&&n.marked.push(t.markText(m.from,m.to,{className:"CodeMirror-lint-mark CodeMirror-lint-mark-"+d,__annotation:m}))}n.hasGutter&&t.setGutterMarker(l,h,function(e,n,t,o,i){var r=document.createElement("div"),a=r;return r.className="CodeMirror-lint-marker CodeMirror-lint-marker-"+t,o&&((a=r.appendChild(document.createElement("div"))).className="CodeMirror-lint-marker CodeMirror-lint-marker-multiple"),0!=i&&p.on(a,"mouseover",function(t){v(e,t,n,a)}),r}(t,c,u,1<s.length,r.tooltips)),r.highlightLines&&t.addLineClass(l,"wrap",g+u)}}r.onUpdateLinting&&r.onUpdateLinting(e,a,t)}}function s(t){var e=t.state.lint;e&&(clearTimeout(e.timeout),e.timeout=setTimeout(function(){l(t)},e.options.delay))}p.defineOption("lint",!1,function(t,e,n){if(n&&n!=p.Init&&(C(t),!1!==t.state.lint.options.lintOnChange&&t.off("change",s),p.off(t.getWrapperElement(),"mouseover",t.state.lint.onMouseOver),clearTimeout(t.state.lint.timeout),delete t.state.lint),e){for(var o=t.getOption("gutters"),i=!1,r=0;r<o.length;++r)o[r]==h&&(i=!0);n=t.state.lint=new a(t,e,i);n.options.lintOnChange&&t.on("change",s),0!=n.options.tooltips&&"gutter"!=n.options.tooltips&&p.on(t.getWrapperElement(),"mouseover",n.onMouseOver),l(t)}}),p.defineExtension("performLint",function(){l(this)})});

View File

@@ -0,0 +1 @@
!function(o){"object"==typeof exports&&"object"==typeof module?o(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],o):o(CodeMirror)}(function(n){"use strict";n.registerHelper("lint","yaml",function(e){var r=[];if(!window.jsyaml)return window.console&&window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run."),r;try{jsyaml.loadAll(e)}catch(o){e=o.mark,e=e?n.Pos(e.line,e.column):n.Pos(0,0);r.push({from:e,to:e,message:o.message})}return r})});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("yaml",function(){var n=new RegExp("\\b(("+["true","false","on","off","yes","no"].join(")|(")+"))$","i");return{token:function(e,i){var t=e.peek(),r=i.escaped;if(i.escaped=!1,"#"==t&&(0==e.pos||/\s/.test(e.string.charAt(e.pos-1))))return e.skipToEnd(),"comment";if(e.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))return"string";if(i.literal&&e.indentation()>i.keyCol)return e.skipToEnd(),"string";if(i.literal&&(i.literal=!1),e.sol()){if(i.keyCol=0,i.pair=!1,i.pairStart=!1,e.match("---"))return"def";if(e.match("..."))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==t?i.inlinePairs++:"}"==t?i.inlinePairs--:"["==t?i.inlineList++:i.inlineList--,"meta";if(0<i.inlineList&&!r&&","==t)return e.next(),"meta";if(0<i.inlinePairs&&!r&&","==t)return i.keyCol=0,i.pair=!1,i.pairStart=!1,e.next(),"meta";if(i.pairStart){if(e.match(/^\s*(\||\>)\s*/))return i.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(0<i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/))return"number";if(e.match(n))return"keyword"}return!i.pair&&e.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)?(i.pair=!0,i.keyCol=e.indentation(),"atom"):i.pair&&e.match(/^:\s*/)?(i.pairStart=!0,"meta"):(i.pairStart=!1,i.escaped="\\"==t,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-yaml","yaml"),e.defineMIME("text/yaml","yaml")});

View File

@@ -0,0 +1 @@
.cm-s-dracula .CodeMirror-gutters,.cm-s-dracula.CodeMirror{background-color:#282a36!important;color:#f8f8f2!important;border:none}.cm-s-dracula .CodeMirror-gutters{color:#282a36}.cm-s-dracula .CodeMirror-cursor{border-left:solid thin #f8f8f0}.cm-s-dracula .CodeMirror-linenumber{color:#6d8a88}.cm-s-dracula .CodeMirror-selected{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::selection,.cm-s-dracula .CodeMirror-line>span::selection,.cm-s-dracula .CodeMirror-line>span>span::selection{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::-moz-selection,.cm-s-dracula .CodeMirror-line>span::-moz-selection,.cm-s-dracula .CodeMirror-line>span>span::-moz-selection{background:rgba(255,255,255,.1)}.cm-s-dracula span.cm-comment{color:#6272a4}.cm-s-dracula span.cm-string,.cm-s-dracula span.cm-string-2{color:#f1fa8c}.cm-s-dracula span.cm-number{color:#bd93f9}.cm-s-dracula span.cm-variable{color:#50fa7b}.cm-s-dracula span.cm-variable-2{color:#fff}.cm-s-dracula span.cm-def{color:#50fa7b}.cm-s-dracula span.cm-operator{color:#ff79c6}.cm-s-dracula span.cm-keyword{color:#ff79c6}.cm-s-dracula span.cm-atom{color:#bd93f9}.cm-s-dracula span.cm-meta{color:#f8f8f2}.cm-s-dracula span.cm-tag{color:#ff79c6}.cm-s-dracula span.cm-attribute{color:#50fa7b}.cm-s-dracula span.cm-qualifier{color:#50fa7b}.cm-s-dracula span.cm-property{color:#66d9ef}.cm-s-dracula span.cm-builtin{color:#50fa7b}.cm-s-dracula span.cm-type,.cm-s-dracula span.cm-variable-3{color:#ffb86c}.cm-s-dracula .CodeMirror-activeline-background{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}

View File

@@ -0,0 +1,457 @@
'use strict';
'require form';
'require fs';
'require poll';
'require rpc';
'require uci';
'require ui';
'require view';
var callServiceList = rpc.declare({
object: 'service',
method: 'list',
params: ['name'],
expect: { '': {} }
});
function getServiceStatus() {
return L.resolveDefault(callServiceList('mosdns'), {}).then(function (res) {
var isRunning = false;
try {
isRunning = res['mosdns']['instances']['mosdns']['running'];
} catch (e) { }
return isRunning;
});
}
function renderStatus(isRunning) {
var spanTemp = '<em><span style="color:%s"><strong>%s %s</strong></span></em>';
var renderHTML;
if (isRunning) {
renderHTML = spanTemp.format('green', _('MosDNS'), _('RUNNING'));
} else {
renderHTML = spanTemp.format('red', _('MosDNS'), _('NOT RUNNING'));
}
return renderHTML;
}
async function loadCodeMirrorResources() {
const styles = [
'/luci-static/resources/codemirror5/theme/dracula.min.css',
'/luci-static/resources/codemirror5/addon/lint/lint.min.css',
'/luci-static/resources/codemirror5/codemirror.min.css',
];
const scripts = [
'/luci-static/resources/codemirror5/libs/js-yaml.min.js',
'/luci-static/resources/codemirror5/codemirror.min.js',
'/luci-static/resources/codemirror5/addon/display/autorefresh.min.js',
'/luci-static/resources/codemirror5/mode/yaml/yaml.min.js',
'/luci-static/resources/codemirror5/addon/lint/lint.min.js',
'/luci-static/resources/codemirror5/addon/lint/yaml-lint.min.js',
];
const loadStyles = async () => {
for (const href of styles) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
};
const loadScripts = async () => {
for (const src of scripts) {
const script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
await new Promise(resolve => script.onload = resolve);
}
};
await loadStyles();
await loadScripts();
}
return view.extend({
load: function () {
return Promise.all([
L.resolveDefault(fs.exec('/usr/bin/mosdns', ['version']), null),
]);
},
handleFlushCache: function (m, section_id, ev) {
return fs.exec('/usr/share/mosdns/mosdns.sh', ['flush'])
.then(function (lazy_cache) {
var res = lazy_cache.code;
if (res === 0) {
ui.addNotification(null, E('p', _('Flushing DNS Cache Success.')), 'info');
} else {
ui.addNotification(null, E('p', _('Flushing DNS Cache Failed, Please check if MosDNS is running.')), 'error');
}
});
},
render: function (basic) {
var m, s, o, v;
v = '';
if (basic[0] && basic[0].code === 0) {
v = basic[0].stdout.trim();
}
m = new form.Map('mosdns', _('MosDNS') + '&#160;' + v,
_('MosDNS is a plugin-based DNS forwarder/traffic splitter.'));
s = m.section(form.TypedSection);
s.anonymous = true;
s.render = function () {
setTimeout(function () {
poll.add(function () {
return L.resolveDefault(getServiceStatus()).then(function (res) {
var view = document.getElementById('service_status');
if (view) {
view.innerHTML = renderStatus(res);
} else {
console.error('Element #service_status not found.');
}
});
});
}, 100);
/* dynamically loading Codemirror resources */
loadCodeMirrorResources();
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
E('p', { id: 'service_status' }, _('Collecting data...'))
]);
}
s = m.section(form.NamedSection, 'config', 'mosdns');
s.tab('basic', _('Basic Options'));
s.tab("advanced", _("Advanced Options"));
s.tab("cloudflare", _("Cloudflare Options"));
s.tab("api", _("API Options"));
s.tab('geodata', _('GeoData Export'));
/* basic */
o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'));
o.default = o.disabled;
o.rmempty = false;
o = s.taboption('basic', form.ListValue, 'configfile', _('Config File'));
o.value('/var/etc/mosdns.json', _('Default Config'));
o.value('/etc/mosdns/config_custom.yaml', _('Custom Config'));
o.default = '/var/etc/mosdns.json';
o = s.taboption('basic', form.Value, 'listen_port', _('Listen port'));
o.default = '5335';
o.datatype = 'port';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.ListValue, 'log_level', _('Log Level'));
o.value('debug', _('Debug'));
o.value('info', _('Info'));
o.value('warn', _('Warning'));
o.value('error', _('Error'));
o.default = 'info';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Value, 'log_file', _('Log File'));
o.placeholder = '/var/log/mosdns.log';
o.default = '/var/log/mosdns.log';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Flag, 'redirect', _('DNS Forward'), _('Forward Dnsmasq Domain Name resolution requests to MosDNS'));
o.default = false;
if (L.hasSystemFeature('firewall4')) {
o = s.taboption('basic', form.Flag, 'local_dns_redirect', _('DNS redirect'), _('Force redirect all local DNS queries to MosDNS, a.k.a. DNS Hijacking'));
o.default = false;
o.depends('redirect', '1');
}
o = s.taboption('basic', form.Flag, 'prefer_ipv4_cn', _('China DNS prefer IPv4'),
_('IPv4 is preferred for China DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'prefer_ipv4', _('Remote DNS prefer IPv4'),
_('IPv4 is preferred for Remote / Streaming Media DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'custom_local_dns', _('Custom China DNS'), _('Follow WAN interface DNS if not enabled'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'apple_optimization', _('Apple domains optimization'),
_('For Apple domains equipped with Chinese mainland CDN, always responsive to Chinese CDN IP addresses'));
o.depends('custom_local_dns', '1');
o.default = false;
o = s.taboption('basic', form.DynamicList, 'local_dns', _('China DNS server'));
o.value('119.29.29.29', _('Tencent Public DNS (119.29.29.29)'));
o.value('119.28.28.28', _('Tencent Public DNS (119.28.28.28)'));
o.value('223.5.5.5', _('Aliyun Public DNS (223.5.5.5)'));
o.value('223.6.6.6', _('Aliyun Public DNS (223.6.6.6)'));
o.value('180.184.1.1', _('TrafficRoute Public DNS (180.184.1.1)'));
o.value('180.184.2.2', _('TrafficRoute Public DNS (180.184.2.2)'));
o.value('114.114.114.114', _('Xinfeng Public DNS (114.114.114.114)'));
o.value('114.114.115.115', _('Xinfeng Public DNS (114.114.115.115)'));
o.value('180.76.76.76', _('Baidu Public DNS (180.76.76.76)'));
o.value('https://doh.pub/dns-query', _('Tencent Public DNS (DNS over HTTPS)'));
o.value('quic://dns.alidns.com', _('Aliyun Public DNS (DNS over QUIC)'));
o.value('https://dns.alidns.com/dns-query', _('Aliyun Public DNS (DNS over HTTPS)'));
o.value('h3://dns.alidns.com/dns-query', _('Aliyun Public DNS (DNS over HTTPS/3)'));
o.value('https://doh.360.cn/dns-query', _('360 Public DNS (DNS over HTTPS)'));
o.default = '119.29.29.29';
o.depends('custom_local_dns', '1');
o = s.taboption('basic', form.DynamicList, 'remote_dns', _('Remote DNS server'));
o.value('tls://1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.value('tls://1.0.0.1', _('CloudFlare Public DNS (1.0.0.1)'));
o.value('tls://8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('tls://8.8.4.4', _('Google Public DNS (8.8.4.4)'));
o.value('tls://9.9.9.9', _('Quad9 Public DNS (9.9.9.9)'));
o.value('tls://149.112.112.112', _('Quad9 Public DNS (149.112.112.112)'));
o.value('tls://208.67.222.222', _('Cisco Public DNS (208.67.222.222)'));
o.value('tls://208.67.220.220', _('Cisco Public DNS (208.67.220.220)'));
o.default = 'tls://8.8.8.8';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Flag, 'custom_stream_media_dns', _('Custom Stream Media DNS'),
_('Netflix, Disney+, Hulu and streaming media rules list will use this DNS'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.DynamicList, 'stream_media_dns', _('Streaming Media DNS server'));
o.value('tls://1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.value('tls://1.0.0.1', _('CloudFlare Public DNS (1.0.0.1)'));
o.value('tls://8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('tls://8.8.4.4', _('Google Public DNS (8.8.4.4)'));
o.value('tls://9.9.9.9', _('Quad9 Public DNS (9.9.9.9)'));
o.value('tls://149.112.112.112', _('Quad9 Public DNS (149.112.112.112)'));
o.value('tls://208.67.222.222', _('Cisco Public DNS (208.67.222.222)'));
o.value('tls://208.67.220.220', _('Cisco Public DNS (208.67.220.220)'));
o.default = 'tls://8.8.8.8';
o.depends('custom_stream_media_dns', '1');
o = s.taboption('basic', form.Value, 'bootstrap_dns', _('Bootstrap DNS servers'),
_('Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams'));
o.value('119.29.29.29', _('Tencent Public DNS (119.29.29.29)'));
o.value('119.28.28.28', _('Tencent Public DNS (119.28.28.28)'));
o.value('223.5.5.5', _('Aliyun Public DNS (223.5.5.5)'));
o.value('223.6.6.6', _('Aliyun Public DNS (223.6.6.6)'));
o.value('114.114.114.114', _('Xinfeng Public DNS (114.114.114.114)'));
o.value('114.114.115.115', _('Xinfeng Public DNS (114.114.115.115)'));
o.value('180.76.76.76', _('Baidu Public DNS (180.76.76.76)'));
o.value('8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.default = '119.29.29.29';
o.depends('configfile', '/var/etc/mosdns.json');
/* advanced */
o = s.taboption('advanced', form.Value, 'concurrent', _('Concurrent'),
_('DNS query request concurrency, The number of upstream DNS servers that are allowed to initiate requests at the same time'));
o.datatype = 'and(uinteger,min(1),max(3))';
o.default = '2';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'idle_timeout', _('Idle Timeout'),
_('DoH/TCP/DoT Connection Multiplexing idle timeout (default 30 seconds)'))
o.datatype = 'and(uinteger,min(1))';
o.default = '30';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'enable_pipeline', _('TCP/DoT Connection Multiplexing'),
_('Enable TCP/DoT RFC 7766 new Query Pipelining connection multiplexing mode'))
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'insecure_skip_verify', _('Disable TLS Certificate'),
_('Disable TLS Servers certificate validation, Can be useful if system CA certificate expires or the system time is out of order'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'enable_ecs_remote',
_('Enable EDNS client subnet'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'remote_ecs_ip', _('IP Address'),
_('Please provide the IP address you use when accessing foreign websites. This IP subnet (0/24) will be used as the ECS address for Remote / Streaming Media DNS requests') +
_('This feature is typically used when using a self-built DNS server as an Remote / Streaming Media DNS upstream (requires support from the upstream server)'));
o.datatype = 'ipaddr';
o.depends('enable_ecs_remote', '1');
o = s.taboption('advanced', form.Flag, 'dns_leak', _('Prevent DNS Leaks'),
_('Enable this option fallback policy forces forwarding to remote DNS'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'cache', _('Enable DNS Cache'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'cache_size', _('DNS Cache Size'));
o.datatype = 'and(uinteger,min(0))';
o.default = 8000;
o.depends('cache', '1');
o = s.taboption('advanced', form.Value, 'lazy_cache_ttl', _('Lazy Cache TTL'),
_('Lazy cache survival time (in second). To disable Lazy Cache, please set to 0.'));
o.datatype = 'and(uinteger,min(0))';
o.default = 86400;
o.depends('cache', '1');
o = s.taboption('advanced', form.Flag, 'dump_file', _('Cache Dump'),
_('Save the cache locally and reload the cache dump on the next startup'));
o.rmempty = false;
o.default = false;
o.depends('cache', '1');
o = s.taboption('advanced', form.Value, 'dump_interval',
_('Auto Save Cache Interval'));
o.datatype = 'and(uinteger,min(0))';
o.default = 3600;
o.depends('dump_file', '1');
o = s.taboption('advanced', form.Value, 'minimal_ttl', _('Minimum TTL'),
_('Modify the Minimum TTL value (seconds) for DNS answer results, 0 indicating no modification'));
o.datatype = 'and(uinteger,min(0),max(604800))';
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'maximum_ttl', _('Maximum TTL'),
_('Modify the Maximum TTL value (seconds) for DNS answer results, 0 indicating no modification'));
o.datatype = 'and(uinteger,min(0),max(604800))';
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'reject_type65', _('Disable RR Type 65 (HTTPS/SVCB)'),
_('Block DNS RR Type 65 records (HTTPS/SVCB, used for HTTP/3, ECH, etc.), force using only A/AAAA records.'));
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'adblock', _('Enable DNS ADblock'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('advanced', form.DynamicList, 'ad_source', _('ADblock Source'),
_('When using custom rule sources, please use rule types supported by MosDNS (domain lists).') +
'<br>' +
_('Support for local files, such as: file:///var/mosdns/example.txt'));
o.depends('adblock', '1');
o.default = 'geosite.dat';
o.value('geosite.dat', 'v2ray-geosite');
o.value('https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt', 'anti-AD')
o.value('https://raw.githubusercontent.com/Cats-Team/AdRules/main/mosdns_adrules.txt', 'Cats-Team/AdRules')
o.value('https://raw.githubusercontent.com/neodevpro/neodevhost/master/domain', 'NEO DEV HOST')
/* cloudflare */
o = s.taboption('cloudflare', form.Flag, 'cloudflare', _('Enabled'),
_('Match the parsing result with the Cloudflare IP ranges, and when there is a successful match, \
use the \'Custom IP\' as the parsing result (experimental feature)'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('cloudflare', form.DynamicList, 'cloudflare_ip', _('Custom IP'));
o.datatype = 'ipaddr';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('cloudflare', form.TextValue, '_cloudflare',
_('Cloudflare IP Ranges'),
_('IPv4 CIDR: <a href="https://www.cloudflare.com/ips-v4" target="_blank">https://www.cloudflare.com/ips-v4</a> <br /> IPv6 CIDR: <a href="https://www.cloudflare.com/ips-v6" target="_blank">https://www.cloudflare.com/ips-v6</a>'));
o.rows = 15;
o.depends('configfile', '/var/etc/mosdns.json');
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/cloudflare-cidr.txt');
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/cloudflare-cidr.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.then(function (i) {
return fs.exec('/etc/init.d/mosdns', ['restart']);
});
});
};
/* api */
o = s.taboption('api', form.Value, 'listen_port_api', _('API Listen port'));
o.datatype = 'and(port,min(1))';
o.default = 9091;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('api', form.Button, '_flush_cache', null,
_('Flushing DNS Cache will clear any IP addresses or DNS records from MosDNS cache.'));
o.title = '&#160;';
o.inputtitle = _('Flush DNS Cache');
o.inputstyle = 'apply';
o.onclick = L.bind(this.handleFlushCache, this, m);
o.depends('cache', '1');
/* configuration */
var configeditor = null;
setTimeout(function () {
var textarea = document.getElementById('widget.cbid.mosdns.config._custom');
if (textarea) {
configeditor = CodeMirror.fromTextArea(textarea, {
autoRefresh: true,
lineNumbers: true,
lineWrapping: true,
lint: true,
gutters: ['CodeMirror-lint-markers'],
matchBrackets: true,
mode: "text/yaml",
styleActiveLine: true,
theme: "dracula"
});
}
}, 600);
o = s.taboption('basic', form.TextValue, '_custom', _('Configuration Editor'),
_('This is the content of the file \'/etc/mosdns/config_custom.yaml\' from which your MosDNS configuration will be generated. \
Only accepts configuration content in yaml format.'));
o.rows = 25;
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/config_custom.yaml');
};
o.write = function (section_id, formvalue) {
if (configeditor) {
var editorContent = configeditor.getValue();
if (editorContent === formvalue) {
return;
}
return fs.write('/etc/mosdns/config_custom.yaml', editorContent.trim().replace(/\r\n/g, '\n') + '\n')
.then(function (i) {
return fs.exec('/etc/init.d/mosdns', ['restart']);
})
.then(function () {
return window.location.reload();
})
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
}
};
o = s.taboption('geodata', form.DynamicList, 'geosite_tags', _('GeoSite Tags'),
_('Enter the GeoSite.dat category to be exported, Allow add multiple tags'),
_('Export directory: /var/mosdns'));
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
o = s.taboption('geodata', form.DynamicList, 'geoip_tags', _('GeoIP Tags'),
_('Enter the GeoIP.dat category to be exported, Allow add multiple tags'),
_('Export directory: /var/mosdns'));
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
return m.render();
}
});

View File

@@ -0,0 +1,70 @@
'use strict';
'require dom';
'require fs';
'require poll';
'require view';
var scrollPosition = 0;
var userScrolled = false;
var logTextarea;
function pollLog() {
return Promise.all([
fs.exec_direct('/usr/share/mosdns/mosdns.sh', ['printlog']).then(function (res) {
return res.trim().split(/\n/).join('\n');
}),
]).then(function (data) {
logTextarea.value = data[0] || _('No log data.');
if (!userScrolled) {
logTextarea.scrollTop = logTextarea.scrollHeight;
} else {
logTextarea.scrollTop = scrollPosition;
}
});
};
return view.extend({
handleCleanLogs: function () {
return fs.exec('/usr/share/mosdns/mosdns.sh', ['cleanlog'])
.catch(function (e) { ui.addNotification(null, E('p', e.message)) });
},
render: function () {
logTextarea = E('textarea', {
'class': 'cbi-input-textarea',
'wrap': 'off',
'readonly': 'readonly',
'style': 'width: calc(100% - 20px);height: 535px;margin: 10px;overflow-y: scroll;',
});
logTextarea.addEventListener('scroll', function () {
userScrolled = true;
scrollPosition = logTextarea.scrollTop;
});
var log_textarea_wrapper = E('div', { 'id': 'log_textarea' }, logTextarea);
poll.add(pollLog);
var clear_logs_button = E('input', { 'class': 'btn cbi-button-action', 'type': 'button', 'style': 'margin-left: 10px; margin-top: 10px;', 'value': _('Clear logs') });
clear_logs_button.addEventListener('click', this.handleCleanLogs.bind(this));
return E([
E('div', { 'class': 'cbi-map' }, [
E('h2', { 'name': 'content' }, '%s - %s'.format(_('MosDNS'), _('Log Data'))),
E('div', { 'class': 'cbi-section' }, [
clear_logs_button,
log_textarea_wrapper,
E('div', { 'style': 'text-align:right' },
E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval))
)
])
])
]);
},
handleSave: null,
handleSaveApply: null,
handleReset: null
});

View File

@@ -0,0 +1,234 @@
'use strict';
'require form';
'require fs';
'require ui';
'require view';
return view.extend({
render: function () {
var m, s, o;
m = new form.Map("mosdns", _("Rule Settings"),
_('The list of rules only apply to \'Default Config\' profiles.'));
s = m.section(form.TypedSection);
s.anonymous = true;
s.sortable = true;
s.tab('whitelist', _('White Lists'));
s.tab('blocklist', _('Block Lists'));
s.tab('greylist', _('Grey Lists'));
s.tab('ddnslist', _('DDNS Lists'));
s.tab('hostslist', _('Hosts'));
s.tab('redirectlist', _('Redirect'));
s.tab('localptrlist', _('Block PTR'));
s.tab('streamingmedialist', _('Streaming Media'));
o = s.taboption('whitelist', form.TextValue, '_whitelist',
null,
'<font color=\'red\'>'
+ _('Added domain names always permit resolution using \'local DNS\' with the highest priority (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/whitelist.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/whitelist.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('blocklist', form.TextValue, '_blocklist',
null,
'<font color=\'red\'>'
+ _('Added domain names will block DNS resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/blocklist.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/blocklist.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('greylist', form.TextValue, '_greylist',
null,
'<font color=\'red\'>'
+ _('Added domain names will always use \'Remote DNS\' for resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/greylist.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/greylist.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('ddnslist', form.TextValue, '_ddnslist',
null,
'<font color=\'red\'>'
+ _('Added domain names will always use \'Local DNS\' for resolution, with a forced TTL of 5 seconds, and results will not be cached (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/ddnslist.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/ddnslist.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('hostslist', form.TextValue, '_hostslist',
null,
'<font color=\'red\'>'
+ _('Custom Hosts rewrite, for example: baidu.com 10.0.0.1 (one rule per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/hosts.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/hosts.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('redirectlist', form.TextValue, '_redirectlist',
null,
'<font color=\'red\'>'
+ _('Redirecting requests for domain names. Request domain A, but return records for domain B, for example: baidu.com qq.com (one rule per line).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/redirect.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/redirect.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('localptrlist', form.TextValue, '_localptrlist',
null,
'<font color=\'red\'>'
+ _('Added domain names will block PTR requests (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/local-ptr.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/local-ptr.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o = s.taboption('streamingmedialist', form.TextValue, '_streamingmedialist',
null,
'<font color=\'red\'>'
+ _('When enabling \'Custom Stream Media DNS\', added domains will always use the \'Streaming Media DNS server\' for resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = function (section_id) {
return fs.trimmed('/etc/mosdns/rule/streaming.txt').catch(function (e) {
return "";
});
};
o.write = function (section_id, formvalue) {
return this.cfgvalue(section_id).then(function (value) {
if (value == formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/streaming.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n')
.catch(function (e) {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
return m.render();
},
handleSaveApply: function (ev) {
var m = this.map;
onclick = L.bind(this.handleSave, this, m);
return fs.exec('/etc/init.d/mosdns', ['restart'])
.then(function () {
window.location.reload();
})
.catch(function (e) {
ui.addNotification(null, E('p', _('Failed to restart mosdns: %s').format(e.message)));
});
},
handleReset: null
});

View File

@@ -0,0 +1,75 @@
'use strict';
'require form';
'require fs';
'require ui';
'require view';
return view.extend({
handleUpdate: function (m, section_id, ev) {
return fs.exec('/usr/share/mosdns/mosdns.sh', ['geodata'])
.then(function (i) {
var res = i.code;
if (res === 0) {
ui.addNotification(null, E('p', _('Update success')), 'info');
} else {
ui.addNotification(null, E('p', i.stderr + '<br />' + i.stdout), 'warn');
ui.addNotification(null, E('p', _('Update failed, Please check the network status')), 'error');
}
});
},
render: function () {
var m, s, o;
m = new form.Map('mosdns', _('Update GeoIP & GeoSite databases'),
_('Automatically update GeoIP and GeoSite databases as well as ad filtering rules through scheduled tasks.'));
s = m.section(form.TypedSection);
s.anonymous = true;
o = s.option(form.Flag, 'geo_auto_update', _('Enable Auto Database Update'));
o.rmempty = false;
o = s.option(form.ListValue, 'geo_update_week_time', _('Update Cycle'));
o.value('*', _('Every Day'));
o.value('1', _('Every Monday'));
o.value('2', _('Every Tuesday'));
o.value('3', _('Every Wednesday'));
o.value('4', _('Every Thursday'));
o.value('5', _('Every Friday'));
o.value('6', _('Every Saturday'));
o.value('0', _('Every Sunday'));
o.default = 3;
o = s.option(form.ListValue, 'geo_update_day_time', _('Update Time'));
for (let t = 0; t < 24; t++) {
o.value(t, t + ':00');
};
o.default = 3;
o = s.option(form.ListValue, 'geoip_type', _('GeoIP Type'),
_('Little: only include Mainland China and Private IP addresses.') +
'<br>' +
_('Full: includes all Countries and Private IP addresses.')
);
o.value('geoip', _('Full'));
o.value('geoip-only-cn-private', _('Little'));
o.rmempty = false;
o.default = 'geoip';
o = s.option(form.Value, 'github_proxy', _('GitHub Proxy'),
_('Update data files with GitHub Proxy, leave blank to disable proxy downloads.'));
o.value('https://gh-proxy.com', _('https://gh-proxy.com'));
o.rmempty = true;
o.default = '';
o = s.option(form.Button, '_udpate', null,
_('Check And Update GeoData.'));
o.title = _('Database Update');
o.inputtitle = _('Check And Update');
o.inputstyle = 'apply';
o.onclick = L.bind(this.handleUpdate, this, m);
return m.render();
}
});