luci-app-aria2: convert to client side
Signed-off-by: Van Waholtz <vanwaholtz@gmail.com>
This commit is contained in:
parent
8d35d78c61
commit
9dda104ee7
14 changed files with 832 additions and 803 deletions
|
@ -7,7 +7,7 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI Support for Aria2
|
||||
LUCI_DEPENDS:=+luci-compat +aria2 +luci-lib-ipkg
|
||||
LUCI_DEPENDS:=+aria2
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_MAINTAINER:=Xingwang Liao <kuoruan@gmail.com>
|
||||
|
|
|
@ -0,0 +1,630 @@
|
|||
'use strict';
|
||||
'require dom';
|
||||
'require form';
|
||||
'require fs';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require tools.widgets as widgets';
|
||||
'require ui';
|
||||
'require view';
|
||||
|
||||
var callServiceList, CBIAria2Status, CBIRpcSecret, CBIRpcUrl;
|
||||
|
||||
callServiceList = rpc.declare({
|
||||
object: 'service',
|
||||
method: 'list',
|
||||
params: [ 'name' ],
|
||||
expect: { '': {} },
|
||||
filter: function (data, args, extra) {
|
||||
var i, res = data[args.name] || {};
|
||||
for (i = 0; (i < extra.length) && (Object.keys(res).length > 0); ++i)
|
||||
res = res[extra[i]] || {};
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
CBIAria2Status = form.DummyValue.extend({
|
||||
renderWidget: function() {
|
||||
var extra = ['instances', 'aria2.main'];
|
||||
var node = E('div', {}, E('p', {}, E('em', {}, _('Collecting data...'))));
|
||||
poll.add(function() {
|
||||
return Promise.all([
|
||||
callServiceList('aria2', extra)
|
||||
.then(function(res) {
|
||||
return E('p', {}, E('em', {}, res.running
|
||||
? _('The Aria2 service is running.')
|
||||
: _('The Aria2 service is not running.'))
|
||||
);
|
||||
}),
|
||||
getWebFrontInstalled()
|
||||
.then(function(installed) {
|
||||
var btns = [E('label'), _('Installed web interface: ')];
|
||||
for (var i in installed) {
|
||||
btns.push(E('button', {
|
||||
'class': 'btn cbi-button',
|
||||
'click': openWebInterface.bind(this, i)
|
||||
}, installed[i]));
|
||||
}
|
||||
return btns.length > 0 ? E('p', btns) : null;
|
||||
})
|
||||
]).then(function(res) {
|
||||
res = res.filter(function(r) { return r ? 1 : 0 });
|
||||
dom.content(node, res);
|
||||
});
|
||||
});
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
||||
CBIRpcSecret = form.Value.extend({
|
||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||
var node = this.super('renderWidget', [section_id, option_index, cfgvalue]);
|
||||
dom.append(node, [
|
||||
E('br'),
|
||||
E('span', { 'class': 'control-group' },
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-neutral',
|
||||
'click': this.clickFn.bind(this, section_id)
|
||||
}, this.btnTitle)
|
||||
)
|
||||
]);
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
||||
CBIRpcUrl = form.DummyValue.extend({
|
||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||
var inputEl = new ui.Textfield('', {'id': this.cbid(section_id), 'readonly': true});
|
||||
return E([inputEl.render(),
|
||||
E('br'),
|
||||
E('span', { 'class': 'control-group' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-neutral',
|
||||
'click': this.clickFn.bind(this, section_id, 0, inputEl)
|
||||
}, 'HTTP(s)'),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-neutral',
|
||||
'click': this.clickFn.bind(this, section_id, 1, inputEl)
|
||||
}, 'WebSocket(s)')
|
||||
])
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
function getToken(section_id) {
|
||||
var len = 32, randomStr = '';
|
||||
var inputLength = prompt(_('Please input token length:'), len);
|
||||
if (inputLength === null || inputLength === '') {
|
||||
return;
|
||||
} else if (/^\d+$/.test(inputLength)) {
|
||||
len = parseInt(inputLength);
|
||||
}
|
||||
|
||||
while(len - randomStr.length > 0) {
|
||||
randomStr += Math.random().toString(36).substring(2, 2 + len - randomStr.length);
|
||||
}
|
||||
document.getElementById('widget.' + this.cbid(section_id)).value = randomStr;
|
||||
};
|
||||
|
||||
function getWebFrontInstalled() {
|
||||
var supported = {'ariang': 'AriaNg', 'webui-aria2': 'WebUI-Aria2', 'yaaw': 'YAAW'};
|
||||
var actions = [];
|
||||
|
||||
for (var s in supported) {
|
||||
actions.push(fs.stat('/www/' + s + '/index.html')
|
||||
.then(L.bind(function(s) { return s; }, this, s))
|
||||
.catch(function(err) { return null; }));
|
||||
}
|
||||
|
||||
return Promise.all(actions).then(function(res) {
|
||||
var installed = {};
|
||||
for (var i = 0; i < res.length; ++i)
|
||||
if (res[i])
|
||||
installed[res[i]] = supported[res[i]];
|
||||
return installed;
|
||||
});
|
||||
}
|
||||
|
||||
function openWebInterface(path) {
|
||||
var host = window.location.host;
|
||||
var protocol = window.location.protocol;
|
||||
window.open(protocol + '//' + host + '/' + path);
|
||||
};
|
||||
|
||||
function showRPCURL(section_id, useWS, inputEl) {
|
||||
var getOptVal = L.bind(function(opt, default_val) {
|
||||
default_val = default_val || null;
|
||||
return this.section.formvalue(section_id, opt) || default_val;
|
||||
}, this);
|
||||
|
||||
var port = getOptVal('rpc_listen_port', 6800);
|
||||
var authMethod = getOptVal('rpc_auth_method', 'none');
|
||||
var secure = JSON.parse(getOptVal('rpc_secure', false));
|
||||
|
||||
var protocol = useWS
|
||||
? (secure ? 'wss' : 'ws')
|
||||
: (secure ? 'https' : 'http');
|
||||
var url = protocol + '://';
|
||||
|
||||
if (authMethod == 'token') {
|
||||
var authToken = getOptVal('rpc_secret');
|
||||
if (authToken)
|
||||
url += 'token:' + authToken + '@';
|
||||
} else if (authMethod == 'user_pass') {
|
||||
var authUser = getOptVal('rpc_user');
|
||||
var authPasswd = getOptVal('rpc_passwd');
|
||||
if (authUser && authPasswd)
|
||||
url += authUser + ':' + authPasswd + '@';
|
||||
}
|
||||
url += window.location.hostname + ':' + port + '/jsonrpc';
|
||||
inputEl.setValue(url);
|
||||
};
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return fs.exec_direct('/usr/bin/aria2c', [ '-v' ]).then(function(res) {
|
||||
var info = {}, lines = res.split(/\r?\n|\r/g);
|
||||
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
if (/^aria2 version/.exec(lines[i])) {
|
||||
info.version = lines[i].match(/(\d+\.){2}\d+/)[0];
|
||||
}
|
||||
else if (/^Enabled Features/.exec(lines[i])) {
|
||||
info.gzip = lines[i].search(/GZip/) >= 0;
|
||||
info.https = lines[i].search(/HTTPS/) >= 0;
|
||||
info.bt = lines[i].search(/BitTorrent/) >= 0;
|
||||
info.sftp = lines[i].search(/SFTP/) >= 0;
|
||||
info.adns = lines[i].search(/Async DNS/) >= 0;
|
||||
info.cookie = lines[i].search(/Firefox3 Cookie/) >= 0;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
});
|
||||
},
|
||||
|
||||
render: function(aria2) {
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('aria2', '%s - %s'.format(_('Aria2'), _('Settings')), '<p>%s</p><p>%s</p>'.format(
|
||||
_('Aria2 is a lightweight multi-protocol & multi-source, cross platform download utility.'),
|
||||
_('For more information, please visit: %s.')
|
||||
.format('<a href="https://aria2.github.io" target="_blank">https://aria2.github.io</a>')));
|
||||
|
||||
s = m.section(form.TypedSection);
|
||||
s.title = '%s - %s'.format(_('Aria2'), _('Running Status'));
|
||||
s.anonymous = true;
|
||||
s.cfgsections = function() { return [ 'status' ] };
|
||||
|
||||
o = s.option(CBIAria2Status);
|
||||
|
||||
s = m.section(form.NamedSection, 'main', 'aria2');
|
||||
s.addremove = false;
|
||||
s.anonymous = true;
|
||||
|
||||
s.tab('basic', _('Basic Options'));
|
||||
|
||||
o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('basic', widgets.UserSelect, 'user', _('Run daemon as user'),
|
||||
_('Leave blank to use default user.'));
|
||||
|
||||
o = s.taboption('basic', form.Value, 'dir', _('Download directory'),
|
||||
_('The directory to store the downloaded file. For example <code>/mnt/sda1</code>.'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('basic', form.Value, 'config_dir', _('Config file directory'),
|
||||
_('The directory to store the config file, session file and DHT file.'));
|
||||
o.placeholder = '/var/etc/aria2';
|
||||
|
||||
o = s.taboption('basic', form.Flag, 'enable_logging', _('Enable logging'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('basic', form.Value, 'log', _('Log file'),
|
||||
_('The file name of the log file.'));
|
||||
o.depends('enable_logging', '1');
|
||||
o.placeholder = '/var/log/aria2.log';
|
||||
|
||||
o = s.taboption('basic', form.ListValue, 'log_level', _('Log level'));
|
||||
o.depends('enable_logging', '1');
|
||||
o.value('debug', _('Debug'));
|
||||
o.value('info', _('Info'));
|
||||
o.value('notice', _('Notice'));
|
||||
o.value('warn', _('Warn'));
|
||||
o.value('error', _('Error'));
|
||||
o.default = 'warn';
|
||||
|
||||
o = s.taboption('basic', form.Value, 'max_concurrent_downloads', _('Max concurrent downloads'));
|
||||
o.placeholder = '5';
|
||||
|
||||
s.tab('rpc', _('RPC Options'))
|
||||
|
||||
o = s.taboption('rpc', form.Flag, 'pause', _('Pause'), _('Pause download after added.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('rpc', form.Flag, 'pause_metadata', _('Pause metadata'),
|
||||
_('Pause downloads created as a result of metadata download.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('rpc', form.Value, 'rpc_listen_port', _('RPC port'));
|
||||
o.datatype = 'range(1024,65535)';
|
||||
o.placeholder = '6800';
|
||||
|
||||
o = s.taboption('rpc', form.ListValue, 'rpc_auth_method', _('RPC authentication method'));
|
||||
o.value('none', _('No Authentication'));
|
||||
o.value('user_pass', _('Username & Password'));
|
||||
o.value('token', _('Token'));
|
||||
|
||||
o = s.taboption('rpc', form.Value, 'rpc_user', _('RPC username'));
|
||||
o.depends('rpc_auth_method', 'user_pass');
|
||||
|
||||
o = s.taboption('rpc', form.Value, 'rpc_passwd', _('RPC password'));
|
||||
o.depends('rpc_auth_method', 'user_pass');
|
||||
o.password = true;
|
||||
|
||||
o = s.taboption('rpc', CBIRpcSecret, 'rpc_secret', _('RPC token'));
|
||||
o.depends('rpc_auth_method', 'token');
|
||||
o.btnTitle = _('Generate Randomly');
|
||||
o.clickFn = getToken;
|
||||
o.password = true;
|
||||
|
||||
if (aria2.https) {
|
||||
o = s.taboption('rpc', form.Flag, 'rpc_secure', _('RPC secure'),
|
||||
_('RPC transport will be encrypted by SSL/TLS. The RPC clients must use https'
|
||||
+ ' scheme to access the server. For WebSocket client, use wss scheme.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('rpc', form.Value, 'rpc_certificate', _('RPC certificate'),
|
||||
_('Use the certificate in FILE for RPC server. The certificate must be either'
|
||||
+ ' in PKCS12 (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the'
|
||||
+ ' certificate, a key and optionally a chain of additional certificates. Only PKCS12'
|
||||
+ ' files with a blank import password can be opened!<br/>When using PEM, you have to'
|
||||
+ ' specify the "RPC private key" as well.'));
|
||||
o.depends('rpc_secure', 'true');
|
||||
o.optional = false;
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('rpc', form.Value, 'rpc_private_key', _('RPC private key'),
|
||||
_('Use the private key in FILE for RPC server. The private key must be'
|
||||
+ ' decrypted and in PEM format.'));
|
||||
o.depends('rpc_secure', 'true');
|
||||
o.optional = false;
|
||||
o.rmempty = false;
|
||||
}
|
||||
|
||||
o = s.taboption('rpc', CBIRpcUrl, '_rpc_url', _('Json-RPC URL'));
|
||||
o.clickFn = showRPCURL;
|
||||
|
||||
s.tab('http', _('HTTP/FTP/SFTP Options'));
|
||||
|
||||
o = s.taboption('http', form.Flag, 'enable_proxy', _('Enable proxy'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('http', form.Value, 'all_proxy', _('All proxy'),
|
||||
_('Use a proxy server for all protocols.'));
|
||||
o.depends('enable_proxy', '1');
|
||||
o.placeholder = '[http://][USER:PASSWORD@]HOST[:PORT]';
|
||||
|
||||
o = s.taboption('http', form.Value, 'all_proxy_user', _('Proxy user'));
|
||||
o.depends('enable_proxy', '1');
|
||||
|
||||
o = s.taboption('http', form.Value, 'all_proxy_passwd', _('Proxy password'));
|
||||
o.depends('enable_proxy', '1');
|
||||
o.password = true;
|
||||
|
||||
if (aria2.https) {
|
||||
o = s.taboption('http', form.Flag, 'check_certificate', _('Check certificate'),
|
||||
_('Verify the peer using certificates specified in "CA certificate" option.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'true';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('http', form.Value, 'ca_certificate', _('CA certificate'),
|
||||
_('Use the certificate authorities in FILE to verify the peers. The certificate'
|
||||
+ ' file must be in PEM format and can contain multiple CA certificates.'));
|
||||
o.depends('check_certificate', 'true');
|
||||
|
||||
o = s.taboption('http', form.Value, 'certificate', _('Certificate'),
|
||||
_('Use the client certificate in FILE. The certificate must be either in PKCS12'
|
||||
+ ' (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the certificate, a'
|
||||
+ ' key and optionally a chain of additional certificates. Only PKCS12 files with a'
|
||||
+ ' blank import password can be opened!<br/>When using PEM, you have to specify the'
|
||||
+ ' "Private key" as well.'));
|
||||
|
||||
o = s.taboption('http', form.Value, 'private_key', _('Private key'),
|
||||
_('Use the private key in FILE. The private key must be decrypted and in PEM'
|
||||
+ ' format. The behavior when encrypted one is given is undefined.'));
|
||||
}
|
||||
|
||||
if (aria2.gzip) {
|
||||
o = s.taboption('http', form.Flag, 'http_accept_gzip', _('HTTP accept gzip'),
|
||||
_('Send <code>Accept: deflate, gzip</code> request header and inflate response'
|
||||
+ ' if remote server responds with <code>Content-Encoding: gzip</code> or'
|
||||
+ ' <code>Content-Encoding: deflate</code>.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
}
|
||||
|
||||
o = s.taboption('http', form.Flag, 'http_no_cache', _('HTTP no cache'),
|
||||
_('Send <code>Cache-Control: no-cache</code> and <code>Pragma: no-cache</code>'
|
||||
+ ' header to avoid cached content. If disabled, these headers are not sent and you'
|
||||
+ ' can add Cache-Control header with a directive you like using "Header" option.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('http', form.DynamicList, 'header', _('Header'),
|
||||
_('Append HEADERs to HTTP request header.'));
|
||||
|
||||
o = s.taboption('http', form.Value, 'connect_timeout', _('Connect timeout'),
|
||||
_('Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server.' +
|
||||
' After the connection is established, this option makes no effect and "Timeout" option is used instead.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '60';
|
||||
|
||||
o = s.taboption('http', form.Value, 'timeout', _('Timeout'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '60';
|
||||
|
||||
o = s.taboption('http', form.Value, 'lowest_speed_limit', _('Lowest speed limit'),
|
||||
'%s %s'.format(
|
||||
_('Close connection if download speed is lower than or equal to this value (bytes per sec). ' +
|
||||
'0 means has no lowest speed limit.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('http', form.Value, 'max_connection_per_server', _('Max connection per server'),
|
||||
_('The maximum number of connections to one server for each download.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '1';
|
||||
|
||||
o = s.taboption('http', form.Value, 'split', _('Max number of split'),
|
||||
_('Download a file using N connections.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '5';
|
||||
|
||||
o = s.taboption('http', form.Value, 'min_split_size', _('Min split size'),
|
||||
_('Don\'t split less than 2*SIZE byte range. Possible values: 1M-1024M.'));
|
||||
o.placeholder = '20M';
|
||||
|
||||
o = s.taboption('http', form.Value, 'max_tries', _('Max tries'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '5';
|
||||
|
||||
o = s.taboption('http', form.Value, 'retry_wait', _('Retry wait'),
|
||||
_('Set the seconds to wait between retries.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('http', form.Value, 'user_agent', _('User agent'),
|
||||
_('Set user agent for HTTP(S) downloads.'));
|
||||
o.placeholder = 'aria2/%s'.format(aria2.version ? aria2.version : '$VERSION');
|
||||
|
||||
if (aria2.bt) {
|
||||
s.tab('bt', _('BitTorrent Options'));
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'enable_dht', _('IPv4 <abbr title="Distributed Hash Table">DHT</abbr> enabled'),
|
||||
'%s %s'.format(
|
||||
_('Enable IPv4 DHT functionality. It also enables UDP tracker support.'),
|
||||
_('This option will be ignored if a private flag is set in a torrent.')
|
||||
));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'true';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'enable_dht6', _('IPv6 <abbr title="Distributed Hash Table">DHT</abbr> enabled'),
|
||||
'%s %s'.format(
|
||||
_('Enable IPv6 DHT functionality.'),
|
||||
_('This option will be ignored if a private flag is set in a torrent.')
|
||||
));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'bt_enable_lpd', _('<abbr title="Local Peer Discovery">LPD</abbr> enabled'),
|
||||
'%s %s'.format(
|
||||
_('Enable Local Peer Discovery.'),
|
||||
_('This option will be ignored if a private flag is set in a torrent.')
|
||||
));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'enable_peer_exchange', _('Enable peer exchange'),
|
||||
'%s %s'.format(
|
||||
_('Enable Peer Exchange extension.'),
|
||||
_('This option will be ignored if a private flag is set in a torrent.')
|
||||
));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'true';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'bt_save_metadata', _('Save metadata'),
|
||||
_('Save meta data as ".torrent" file. This option has effect only when BitTorrent'
|
||||
+ ' Magnet URI is used. The file name is hex encoded info hash with suffix ".torrent".'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'bt_remove_unselected_file', _('Remove unselected file'),
|
||||
_('Removes the unselected files when download is completed in BitTorrent. Please'
|
||||
+ ' use this option with care because it will actually remove files from your disk.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('bt', form.Flag, 'bt_seed_unverified', _('Seed unverified'),
|
||||
_('Seed previously downloaded files without verifying piece hashes.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'listen_port', _('BitTorrent listen port'),
|
||||
_('Set TCP port number for BitTorrent downloads. Accept format: "6881,6885",'
|
||||
+ ' "6881-6999" and "6881-6889,6999". Make sure that the specified ports are open'
|
||||
+ ' for incoming TCP traffic.'));
|
||||
o.placeholder = '6881-6999';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'dht_listen_port', _('DHT Listen port'),
|
||||
_('Set UDP listening port used by DHT (IPv4, IPv6) and UDP tracker. Make sure that the '
|
||||
+ 'specified ports are open for incoming UDP traffic.'));
|
||||
o.depends('enable_dht', 'true');
|
||||
o.depends('enable_dht6', 'true');
|
||||
o.placeholder = '6881-6999';
|
||||
|
||||
o = s.taboption('bt', form.ListValue, 'follow_torrent', _('Follow torrent'));
|
||||
o.value('true', _('True'));
|
||||
o.value('false', _('False'));
|
||||
o.value('mem', _('Keep in memory'));
|
||||
|
||||
o = s.taboption('bt', form.Value, 'max_overall_upload_limit', _('Max overall upload limit'),
|
||||
'%s %s'.format(
|
||||
_('Set max overall upload speed in bytes/sec. 0 means unrestricted.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'max_upload_limit', _('Max upload limit'),
|
||||
'%s %s'.format(
|
||||
_('Set max upload speed per each torrent in bytes/sec. 0 means unrestricted.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'bt_max_open_files', _('Max open files'),
|
||||
_('Specify maximum number of files to open in multi-file BitTorrent download globally.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '100';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'bt_max_peers', _('Max peers'),
|
||||
_('Specify the maximum number of peers per torrent, 0 means unlimited.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '55';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'bt_request_peer_speed_limit', _('Request peer speed limit'),
|
||||
'%s %s'.format(
|
||||
_('If the whole download speed of every torrent is lower than SPEED, aria2'
|
||||
+ ' temporarily increases the number of peers to try for more download speed.'
|
||||
+ ' Configuring this option with your preferred download speed can increase your'
|
||||
+ ' download speed in some cases.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '50K';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'bt_stop_timeout', _('Stop timeout'),
|
||||
_('Stop BitTorrent download if download speed is 0 in consecutive N seconds. If 0 is'
|
||||
+ ' given, this feature is disabled.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'peer_id_prefix', _('Prefix of peer ID'),
|
||||
_('Specify the prefix of peer ID. The peer ID in BitTorrent is 20 byte length.'
|
||||
+ ' If more than 20 bytes are specified, only first 20 bytes are used. If less than 20'
|
||||
+ ' bytes are specified, random byte data are added to make its length 20 bytes.'));
|
||||
o.placeholder = 'A2-%s-'.format(
|
||||
aria2.version ? aria2.version.replace(/\./g, '-') : '$MAJOR-$MINOR-$PATCH'
|
||||
);
|
||||
|
||||
o = s.taboption('bt', form.Value, 'seed_ratio', _('Seed ratio'),
|
||||
_('Specify share ratio. Seed completed torrents until share ratio reaches RATIO.'
|
||||
+ ' You are strongly encouraged to specify equals or more than 1.0 here. Specify 0.0 if'
|
||||
+ ' you intend to do seeding regardless of share ratio.'));
|
||||
o.datatype = 'ufloat';
|
||||
o.placeholder = '1.0';
|
||||
|
||||
o = s.taboption('bt', form.Value, 'seed_time', _('Seed time'),
|
||||
_('Specify seeding time in minutes. If "Seed ratio" option is'
|
||||
+ ' specified along with this option, seeding ends when at least one of the conditions'
|
||||
+ ' is satisfied. Specifying 0 disables seeding after download completed.'));
|
||||
o.datatype = 'ufloat';
|
||||
|
||||
o = s.taboption('bt', form.DynamicList, 'bt_tracker', _('Additional BT tracker'),
|
||||
_('List of additional BitTorrent tracker\'s announce URI.'));
|
||||
o.placeholder = 'http://tracker.example.com/announce';
|
||||
}
|
||||
|
||||
s.tab('advance', _('Advanced Options'));
|
||||
|
||||
o = s.taboption('advance', form.Flag, 'disable_ipv6', _('IPv6 disabled'),
|
||||
_('Disable IPv6. This is useful if you have to use broken DNS and want to avoid terribly'
|
||||
+ ' slow AAAA record lookup.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('advance', form.Value, 'auto_save_interval', _('Auto save interval'),
|
||||
_('Save a control file (*.aria2) every N seconds. If 0 is given, a control file is not'
|
||||
+ ' saved during download.'));
|
||||
o.datatype = 'range(0, 600)';
|
||||
o.placeholder = '60';
|
||||
|
||||
o = s.taboption('advance', form.Value, 'save_session_interval', _('Save session interval'),
|
||||
_('Save error/unfinished downloads to session file every N seconds. If 0 is given, file'
|
||||
+ ' will be saved only when aria2 exits.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('advance', form.Value, 'disk_cache', _('Disk cache'),
|
||||
'%s %s'.format(
|
||||
_('Enable disk cache (in bytes), set 0 to disabled.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '16M';
|
||||
|
||||
o = s.taboption('advance', form.ListValue, 'file_allocation', _('File allocation'),
|
||||
_('Specify file allocation method. If you are using newer file systems such as ext4'
|
||||
+ ' (with extents support), btrfs, xfs or NTFS (MinGW build only), "falloc" is your best choice.'
|
||||
+ ' It allocates large(few GiB) files almost instantly, but it may not be available if your system'
|
||||
+ ' doesn\'t have posix_fallocate(3) function. Don\'t use "falloc" with legacy file systems such as'
|
||||
+ ' ext3 and FAT32 because it takes almost same time as "prealloc" and it blocks aria2 entirely'
|
||||
+ ' until allocation finishes.'));
|
||||
o.value('none', _('None'));
|
||||
o.value('prealloc', _('prealloc'));
|
||||
o.value('trunc', _('trunc'));
|
||||
o.value('falloc', _('falloc'));
|
||||
o.default = 'prealloc';
|
||||
|
||||
o = s.taboption('advance', form.Flag, 'force_save', _('Force save'),
|
||||
_('Save download to session file even if the download is completed or removed.'
|
||||
+ ' This option also saves control file in that situations. This may be useful to save'
|
||||
+ ' BitTorrent seeding which is recognized as completed state.'));
|
||||
o.enabled = 'true';
|
||||
o.disabled = 'false';
|
||||
o.default = 'false';
|
||||
|
||||
o = s.taboption('advance', form.Value, 'max_overall_download_limit', _('Max overall download limit'),
|
||||
'%s %s'.format(
|
||||
_('Set max overall download speed in bytes/sec. 0 means unrestricted.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '0';
|
||||
|
||||
o = s.taboption('advance', form.Value, 'max_download_limit', _('Max download limit'),
|
||||
'%s %s'.format(
|
||||
_('Set max download speed per each download in bytes/sec. 0 means unrestricted.'),
|
||||
_('You can append K or M.')
|
||||
));
|
||||
o.placeholder = '0';
|
||||
|
||||
s = m.section(form.NamedSection, 'main', 'aria2', _('Extra Settings'),
|
||||
_('Settings in this section will be added to config file.'));
|
||||
s.addremove = false;
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.DynamicList, 'extra_settings', _('Settings list'),
|
||||
_('List of extra settings. Format: option=value, eg. <code>netrc-path=/tmp/.netrc</code>.'));
|
||||
o.placeholder = 'option=value';
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
'require fs';
|
||||
'require view';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
var list_files = ['conf', 'session'],
|
||||
actions = [];
|
||||
for (var index = 0; index < list_files.length; ++index) {
|
||||
actions.push(
|
||||
fs.exec_direct('/usr/libexec/aria2-call', [ 'cat', list_files[index] ])
|
||||
.then(function(json) {
|
||||
var res = {};
|
||||
|
||||
try { res = JSON.parse(json); }
|
||||
catch(err) {}
|
||||
|
||||
res.file = res.file || '';
|
||||
res.content = 'content' in res ? res.content.trim() : '';
|
||||
res.rows = res.content.split('\n', 20).length;
|
||||
return res;
|
||||
})
|
||||
);
|
||||
}
|
||||
return Promise.all(actions);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var textareaEl = function(id, data, descr) {
|
||||
return E('div', {'class': 'cbi-section'}, [
|
||||
E('div', {'class': 'cbi-section-descr'}, descr.format(data.file)),
|
||||
E('div', { 'id' : id},
|
||||
E('textarea', {
|
||||
'id': 'widget.' + id,
|
||||
'style': 'width: 100%',
|
||||
'readonly': true,
|
||||
'wrap': 'off',
|
||||
'rows': data.rows >= 20 ? 20 : data.rows + 1
|
||||
}, data.content)
|
||||
)
|
||||
]);
|
||||
};
|
||||
|
||||
return E('div', {'class': 'cbi-map'}, [
|
||||
E('h2', {'name': 'content'}, '%s - %s'.format(_('Aria2'), _('Files'))),
|
||||
E('div', {'class': 'cbi-map-descr'}, _('Here shows the files used by aria2.')),
|
||||
textareaEl('config_area', data[0], _('Content of config file: <code>%s</code>')),
|
||||
textareaEl('session_area', data[1], _('Content of session file: <code>%s</code>'))
|
||||
]);
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
|
@ -0,0 +1,72 @@
|
|||
'use strict';
|
||||
'require dom';
|
||||
'require fs';
|
||||
'require poll';
|
||||
'require view';
|
||||
|
||||
var css = ' \
|
||||
#log_textarea { \
|
||||
padding: 10px; \
|
||||
text-align: left; \
|
||||
} \
|
||||
#log_textarea pre { \
|
||||
padding: .5rem; \
|
||||
word-break: break-all; \
|
||||
margin: 0; \
|
||||
} \
|
||||
.description { \
|
||||
background-color: #33ccff; \
|
||||
}';
|
||||
|
||||
function pollLog(e) {
|
||||
return Promise.all([
|
||||
fs.exec_direct('/usr/libexec/aria2-call', [ 'tail' ]).then(function(res) {
|
||||
return res.trim().split(/\n/).reverse().join('\n')
|
||||
}),
|
||||
fs.exec_direct('/sbin/logread', [ '-e', 'aria2' ]).then(function(res) {
|
||||
return res.trim().split(/\n/).reverse().slice(0, 50).join('\n')
|
||||
})
|
||||
]).then(function(data) {
|
||||
var t = E('pre', { 'wrap': 'pre' }, [
|
||||
E('div', { 'class': 'description' }, _('Last 50 lines of log file:')),
|
||||
E('br'),
|
||||
data[0] || _('No log data.'),
|
||||
E('br'),
|
||||
E('br'),
|
||||
E('div', { 'class': 'description' }, _('Last 50 lines of syslog:')),
|
||||
E('br'),
|
||||
data[1] || _('No log data.')
|
||||
]);
|
||||
dom.content(e, t);
|
||||
});
|
||||
};
|
||||
|
||||
return view.extend({
|
||||
render: function() {
|
||||
var log_textarea = E('div', { 'id': 'log_textarea' },
|
||||
E('img', {
|
||||
'src': L.resource(['icons/loading.gif']),
|
||||
'alt': _('Loading'),
|
||||
'style': 'vertical-align:middle'
|
||||
}, _('Collecting data...'))
|
||||
);
|
||||
|
||||
poll.add(pollLog.bind(this, log_textarea));
|
||||
return E([
|
||||
E('style', [ css ]),
|
||||
E('div', {'class': 'cbi-map'}, [
|
||||
E('h2', {'name': 'content'}, '%s - %s'.format(_('Aria2'), _('Log Data'))),
|
||||
E('div', {'class': 'cbi-section'}, [
|
||||
log_textarea,
|
||||
E('div', {'style': 'text-align:right'},
|
||||
E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval))
|
||||
)
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
|
@ -1,62 +0,0 @@
|
|||
-- Copyright 2016-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the MIT License.
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local http = require "luci.http"
|
||||
local util = require "luci.util"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
module("luci.controller.aria2", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/aria2") then
|
||||
return
|
||||
end
|
||||
|
||||
local e = entry({"admin", "services", "aria2"}, firstchild(), _("Aria2"))
|
||||
e.dependent = false
|
||||
e.acl_depends = { "luci-app-aria2" }
|
||||
|
||||
entry({"admin", "services", "aria2", "config"},
|
||||
cbi("aria2/config"), _("Configuration"), 1)
|
||||
|
||||
entry({"admin", "services", "aria2", "file"},
|
||||
form("aria2/files"), _("Files"), 2)
|
||||
|
||||
entry({"admin", "services", "aria2", "log"},
|
||||
firstchild(), _("Log"), 3)
|
||||
|
||||
entry({"admin", "services", "aria2", "log", "view"},
|
||||
template("aria2/log_template"))
|
||||
|
||||
entry({"admin", "services", "aria2", "log", "read"},
|
||||
call("action_log_read"))
|
||||
|
||||
entry({"admin", "services", "aria2", "status"},
|
||||
call("action_status"))
|
||||
|
||||
end
|
||||
|
||||
function action_status()
|
||||
local status = {
|
||||
running = (sys.call("pidof aria2c >/dev/null") == 0)
|
||||
}
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(status)
|
||||
end
|
||||
|
||||
function action_log_read()
|
||||
local data = { log = "", syslog = "" }
|
||||
|
||||
local log_file = uci:get("aria2", "main", "log") or "/var/log/aria2.log"
|
||||
if fs.access(log_file) then
|
||||
data.log = util.trim(sys.exec("tail -n 50 %s | sed 'x;1!H;$!d;x'" % log_file))
|
||||
end
|
||||
|
||||
data.syslog = util.trim(sys.exec("logread | grep aria2 | tail -n 50 | sed 'x;1!H;$!d;x'"))
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(data)
|
||||
end
|
|
@ -1,491 +0,0 @@
|
|||
-- Copyright 2017-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the MIT License.
|
||||
|
||||
local sys = require "luci.sys"
|
||||
local util = require "luci.util"
|
||||
|
||||
local m, s, o
|
||||
|
||||
local function aria2_info()
|
||||
if sys.call("command -v aria2c >/dev/null") ~= 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local info = {}
|
||||
local line
|
||||
for line in util.execi("aria2c -v 2>/dev/null | grep -E '^(aria2 version|Enabled Features)'") do
|
||||
if line:match("^aria2 version") then
|
||||
local _, _, v = line:find("([%d%.]+)$")
|
||||
info.version = v
|
||||
elseif line:match("^Enabled Features") then
|
||||
info.gzip = line:find("GZip") ~= nil
|
||||
info.https = line:find("HTTPS") ~= nil
|
||||
info.bt = line:find("BitTorrent") ~= nil
|
||||
info.sftp = line:find("SFTP") ~= nil
|
||||
info.adns = line:find("Async DNS") ~= nil
|
||||
info.cookie = line:find("Firefox3 Cookie") ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
return info
|
||||
end
|
||||
|
||||
local aria2 = aria2_info()
|
||||
|
||||
m = Map("aria2", "%s - %s" % { translate("Aria2"), translate("Settings") },
|
||||
"<p>%s</p><p>%s</p>" % {
|
||||
translate("Aria2 is a lightweight multi-protocol & multi-source, cross platform download utility."),
|
||||
translatef("For more information, please visit: %s",
|
||||
"<a href=\"https://aria2.github.io\" target=\"_blank\">https://aria2.github.io</a>")
|
||||
})
|
||||
|
||||
if not aria2 then
|
||||
m:section(SimpleSection, nil, "<span style=\"color: red;\">%s</span>" %
|
||||
translate("Error: Can't find aria2c in PATH, please reinstall aria2."))
|
||||
m.reset = false
|
||||
m.submit = false
|
||||
return m
|
||||
end
|
||||
|
||||
m:append(Template("aria2/settings_header"))
|
||||
|
||||
s = m:section(NamedSection, "main", "aria2")
|
||||
s.addremove = false
|
||||
s.anonymous = true
|
||||
|
||||
s:tab("basic", translate("Basic Options"))
|
||||
|
||||
o = s:taboption("basic", Flag, "enabled", translate("Enabled"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("basic", ListValue, "user", translate("Run daemon as user"),
|
||||
translate("Leave blank to use default user."))
|
||||
o:value("")
|
||||
local user
|
||||
for user in util.execi("cat /etc/passwd | cut -d':' -f1") do
|
||||
o:value(user)
|
||||
end
|
||||
|
||||
o = s:taboption("basic", Value, "dir", translate("Download directory"),
|
||||
translate("The directory to store the downloaded file. For example <code>/mnt/sda1</code>."))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("basic", Value, "config_dir", translate("Config file directory"),
|
||||
translate("The directory to store the config file, session file and DHT file."))
|
||||
o.placeholder = "/var/etc/aria2"
|
||||
|
||||
o = s:taboption("basic", Flag, "enable_logging", translate("Enable logging"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("basic", Value, "log", translate("Log file"),
|
||||
translate("The file name of the log file."))
|
||||
o:depends("enable_logging", "1")
|
||||
o.placeholder = "/var/log/aria2.log"
|
||||
|
||||
o = s:taboption("basic", ListValue, "log_level", translate("Log level"))
|
||||
o:depends("enable_logging", "1")
|
||||
o:value("debug", translate("Debug"))
|
||||
o:value("info", translate("Info"))
|
||||
o:value("notice", translate("Notice"))
|
||||
o:value("warn", translate("Warn"))
|
||||
o:value("error", translate("Error"))
|
||||
o.default = "warn"
|
||||
|
||||
o = s:taboption("basic", Value, "max_concurrent_downloads", translate("Max concurrent downloads"))
|
||||
o.placeholder = "5"
|
||||
|
||||
s:tab("rpc", translate("RPC Options"))
|
||||
|
||||
o = s:taboption("rpc", Flag, "pause", translate("Pause"), translate("Pause download after added."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("rpc", Flag, "pause_metadata", translate("Pause metadata"),
|
||||
translate("Pause downloads created as a result of metadata download."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_listen_port", translate("RPC port"))
|
||||
o.datatype = "range(1024,65535)"
|
||||
o.placeholder = "6800"
|
||||
|
||||
o = s:taboption("rpc", ListValue, "rpc_auth_method", translate("RPC authentication method"))
|
||||
o:value("none", translate("No Authentication"))
|
||||
o:value("user_pass", translate("Username & Password"))
|
||||
o:value("token", translate("Token"))
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_user", translate("RPC username"))
|
||||
o:depends("rpc_auth_method", "user_pass")
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_passwd", translate("RPC password"))
|
||||
o:depends("rpc_auth_method", "user_pass")
|
||||
o.password = true
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_secret", translate("RPC token"))
|
||||
o:depends("rpc_auth_method", "token")
|
||||
o.template = "aria2/value_with_btn"
|
||||
o.btntext = translate("Generate Randomly")
|
||||
o.btnclick = "randomToken();"
|
||||
|
||||
if aria2.https then
|
||||
o = s:taboption("rpc", Flag, "rpc_secure", translate("RPC secure"),
|
||||
translate("RPC transport will be encrypted by SSL/TLS. The RPC clients must use https"
|
||||
.. " scheme to access the server. For WebSocket client, use wss scheme."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_certificate", translate("RPC certificate"),
|
||||
translate("Use the certificate in FILE for RPC server. The certificate must be either"
|
||||
.. " in PKCS12 (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the"
|
||||
.. " certificate, a key and optionally a chain of additional certificates. Only PKCS12"
|
||||
.. " files with a blank import password can be opened!<br/>When using PEM, you have to"
|
||||
.. " specify the \"RPC private key\" as well."))
|
||||
o:depends("rpc_secure", "true")
|
||||
o.datatype = "file"
|
||||
|
||||
o = s:taboption("rpc", Value, "rpc_private_key", translate("RPC private key"),
|
||||
translate("Use the private key in FILE for RPC server. The private key must be"
|
||||
.. " decrypted and in PEM format."))
|
||||
o:depends("rpc_secure", "true")
|
||||
o.datatype = "file"
|
||||
end
|
||||
|
||||
o = s:taboption("rpc", Flag, "_use_ws", translate("Use WebSocket"))
|
||||
|
||||
o = s:taboption("rpc", Value, "_rpc_url", translate("Json-RPC URL"))
|
||||
o.template = "aria2/value_with_btn"
|
||||
o.onmouseover = "this.focus();this.select();"
|
||||
o.btntext = translate("Show URL")
|
||||
o.btnclick = "showRPCURL();"
|
||||
|
||||
s:tab("http", translate("HTTP/FTP/SFTP Options"))
|
||||
|
||||
o = s:taboption("http", Flag, "enable_proxy", translate("Enable proxy"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("http", Value, "all_proxy", translate("All proxy"),
|
||||
translate("Use a proxy server for all protocols."))
|
||||
o:depends("enable_proxy", "1")
|
||||
o.placeholder = "[http://][USER:PASSWORD@]HOST[:PORT]"
|
||||
|
||||
o = s:taboption("http", Value, "all_proxy_user", translate("Proxy user"))
|
||||
o:depends("enable_proxy", "1")
|
||||
|
||||
o = s:taboption("http", Value, "all_proxy_passwd", translate("Proxy password"))
|
||||
o:depends("enable_proxy", "1")
|
||||
o.password = true
|
||||
|
||||
if aria2.https then
|
||||
o = s:taboption("http", Flag, "check_certificate", translate("Check certificate"),
|
||||
translate("Verify the peer using certificates specified in \"CA certificate\" option."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "true"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("http", Value, "ca_certificate", translate("CA certificate"),
|
||||
translate("Use the certificate authorities in FILE to verify the peers. The certificate"
|
||||
.. " file must be in PEM format and can contain multiple CA certificates."))
|
||||
o:depends("check_certificate", "true")
|
||||
o.datatype = "file"
|
||||
|
||||
o = s:taboption("http", Value, "certificate", translate("Certificate"),
|
||||
translate("Use the client certificate in FILE. The certificate must be either in PKCS12"
|
||||
.. " (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the certificate, a"
|
||||
.. " key and optionally a chain of additional certificates. Only PKCS12 files with a"
|
||||
.. " blank import password can be opened!<br/>When using PEM, you have to specify the"
|
||||
.. " \"Private key\" as well."))
|
||||
o.datatype = "file"
|
||||
|
||||
o = s:taboption("http", Value, "private_key", translate("Private key"),
|
||||
translate("Use the private key in FILE. The private key must be decrypted and in PEM"
|
||||
.. " format. The behavior when encrypted one is given is undefined."))
|
||||
o.datatype = "file"
|
||||
end
|
||||
|
||||
if aria2.gzip then
|
||||
o = s:taboption("http", Flag, "http_accept_gzip", translate("HTTP accept gzip"),
|
||||
translate("Send <code>Accept: deflate, gzip</code> request header and inflate response"
|
||||
.. " if remote server responds with <code>Content-Encoding: gzip</code> or"
|
||||
.. " <code>Content-Encoding: deflate</code>."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
end
|
||||
|
||||
o = s:taboption("http", Flag, "http_no_cache", translate("HTTP no cache"),
|
||||
translate("Send <code>Cache-Control: no-cache</code> and <code>Pragma: no-cache</code>"
|
||||
.. " header to avoid cached content. If disabled, these headers are not sent and you"
|
||||
.. " can add Cache-Control header with a directive you like using \"Header\" option."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("http", DynamicList, "header", translate("Header"),
|
||||
translate("Append HEADERs to HTTP request header."))
|
||||
|
||||
o = s:taboption("http", Value, "connect_timeout", translate("Connect timeout"),
|
||||
translate("Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server." ..
|
||||
" After the connection is established, this option makes no effect and \"Timeout\" option is used instead."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "60"
|
||||
|
||||
o = s:taboption("http", Value, "timeout", translate("Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "60"
|
||||
|
||||
o = s:taboption("http", Value, "lowest_speed_limit", translate("Lowest speed limit"),
|
||||
"%s %s" % {
|
||||
translate("Close connection if download speed is lower than or equal to this value (bytes per sec). " ..
|
||||
"0 means has no lowest speed limit."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("http", Value, "max_connection_per_server", translate("Max connection per server"),
|
||||
translate("The maximum number of connections to one server for each download."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "1"
|
||||
|
||||
o = s:taboption("http", Value, "split", translate("Max number of split"),
|
||||
translate("Download a file using N connections."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "5"
|
||||
|
||||
o = s:taboption("http", Value, "min_split_size", translate("Min split size"),
|
||||
translate("Don't split less than 2*SIZE byte range. Possible values: 1M-1024M."))
|
||||
o.placeholder = "20M"
|
||||
|
||||
o = s:taboption("http", Value, "max_tries", translate("Max tries"))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "5"
|
||||
|
||||
o = s:taboption("http", Value, "retry_wait", translate("Retry wait"),
|
||||
translate("Set the seconds to wait between retries."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("http", Value, "user_agent", translate("User agent"),
|
||||
translate("Set user agent for HTTP(S) downloads."))
|
||||
o.placeholder = "aria2/%s" % { aria2.version and aria2.version or "$VERSION" }
|
||||
|
||||
if aria2.bt then
|
||||
s:tab("bt", translate("BitTorrent Options"))
|
||||
|
||||
o = s:taboption("bt", Flag, "enable_dht", translate("IPv4 <abbr title=\"Distributed Hash Table\">DHT</abbr> enabled"),
|
||||
"%s %s" % {
|
||||
translate("Enable IPv4 DHT functionality. It also enables UDP tracker support."),
|
||||
translate("This option will be ignored if a private flag is set in a torrent.")
|
||||
})
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "true"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("bt", Flag, "enable_dht6", translate("IPv6 <abbr title=\"Distributed Hash Table\">DHT</abbr> enabled"),
|
||||
"%s %s" % {
|
||||
translate("Enable IPv6 DHT functionality."),
|
||||
translate("This option will be ignored if a private flag is set in a torrent.")
|
||||
})
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
|
||||
o = s:taboption("bt", Flag, "bt_enable_lpd", translate("<abbr title=\"Local Peer Discovery\">LPD</abbr> enabled"),
|
||||
"%s %s" % {
|
||||
translate("Enable Local Peer Discovery."),
|
||||
translate("This option will be ignored if a private flag is set in a torrent.")
|
||||
})
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("bt", Flag, "enable_peer_exchange", translate("Enable peer exchange"),
|
||||
"%s %s" % {
|
||||
translate("Enable Peer Exchange extension."),
|
||||
translate("This option will be ignored if a private flag is set in a torrent.")
|
||||
})
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "true"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("bt", Flag, "bt_save_metadata", translate("Save metadata"),
|
||||
translate("Save meta data as \".torrent\" file. This option has effect only when BitTorrent"
|
||||
.. " Magnet URI is used. The file name is hex encoded info hash with suffix \".torrent\"."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("bt", Flag, "bt_remove_unselected_file", translate("Remove unselected file"),
|
||||
translate("Removes the unselected files when download is completed in BitTorrent. Please"
|
||||
.. " use this option with care because it will actually remove files from your disk."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("bt", Flag, "bt_seed_unverified", translate("Seed unverified"),
|
||||
translate("Seed previously downloaded files without verifying piece hashes."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("bt", Value, "listen_port", translate("BitTorrent listen port"),
|
||||
translate("Set TCP port number for BitTorrent downloads. Accept format: \"6881,6885\","
|
||||
.. " \"6881-6999\" and \"6881-6889,6999\". Make sure that the specified ports are open"
|
||||
.. " for incoming TCP traffic."))
|
||||
o.placeholder = "6881-6999"
|
||||
|
||||
o = s:taboption("bt", Value, "dht_listen_port", translate("DHT Listen port"),
|
||||
translate("Set UDP listening port used by DHT (IPv4, IPv6) and UDP tracker. Make sure that the "
|
||||
.. "specified ports are open for incoming UDP traffic."))
|
||||
o:depends("enable_dht", "true")
|
||||
o:depends("enable_dht6", "true")
|
||||
o.placeholder = "6881-6999"
|
||||
|
||||
o = s:taboption("bt", ListValue, "follow_torrent", translate("Follow torrent"))
|
||||
o:value("true", translate("True"))
|
||||
o:value("false", translate("False"))
|
||||
o:value("mem", translate("Keep in memory"))
|
||||
|
||||
o = s:taboption("bt", Value, "max_overall_upload_limit", translate("Max overall upload limit"),
|
||||
"%s %s" % {
|
||||
translate("Set max overall upload speed in bytes/sec. 0 means unrestricted."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("bt", Value, "max_upload_limit", translate("Max upload limit"),
|
||||
"%s %s" % {
|
||||
translate("Set max upload speed per each torrent in bytes/sec. 0 means unrestricted."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("bt", Value, "bt_max_open_files", translate("Max open files"),
|
||||
translate("Specify maximum number of files to open in multi-file BitTorrent download globally."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "100"
|
||||
|
||||
o = s:taboption("bt", Value, "bt_max_peers", translate("Max peers"),
|
||||
translate("Specify the maximum number of peers per torrent, 0 means unlimited."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "55"
|
||||
|
||||
o = s:taboption("bt", Value, "bt_request_peer_speed_limit", translate("Request peer speed limit"),
|
||||
"%s %s" % {
|
||||
translate("If the whole download speed of every torrent is lower than SPEED, aria2"
|
||||
.. " temporarily increases the number of peers to try for more download speed."
|
||||
.. " Configuring this option with your preferred download speed can increase your"
|
||||
.. " download speed in some cases."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "50K"
|
||||
|
||||
o = s:taboption("bt", Value, "bt_stop_timeout", translate("Stop timeout"),
|
||||
translate("Stop BitTorrent download if download speed is 0 in consecutive N seconds. If 0 is"
|
||||
.. " given, this feature is disabled."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("bt", Value, "peer_id_prefix", translate("Prefix of peer ID"),
|
||||
translate("Specify the prefix of peer ID. The peer ID in BitTorrent is 20 byte length."
|
||||
.. " If more than 20 bytes are specified, only first 20 bytes are used. If less than 20"
|
||||
.. " bytes are specified, random byte data are added to make its length 20 bytes."))
|
||||
o.placeholder = "A2-%s-" % {
|
||||
aria2.version and string.gsub(aria2.version, "%.", "-") or "$MAJOR-$MINOR-$PATCH"
|
||||
}
|
||||
|
||||
o = s:taboption("bt", Value, "seed_ratio", translate("Seed ratio"),
|
||||
translate("Specify share ratio. Seed completed torrents until share ratio reaches RATIO."
|
||||
.. " You are strongly encouraged to specify equals or more than 1.0 here. Specify 0.0 if"
|
||||
.. " you intend to do seeding regardless of share ratio."))
|
||||
o.datatype = "ufloat"
|
||||
o.placeholder = "1.0"
|
||||
|
||||
o = s:taboption("bt", Value, "seed_time", translate("Seed time"),
|
||||
translate("Specify seeding time in minutes. If \"Seed ratio\" option is"
|
||||
.. " specified along with this option, seeding ends when at least one of the conditions"
|
||||
.. " is satisfied. Specifying 0 disables seeding after download completed."))
|
||||
o.datatype = "ufloat"
|
||||
|
||||
o = s:taboption("bt", DynamicList, "bt_tracker", translate("Additional BT tracker"),
|
||||
translate("List of additional BitTorrent tracker's announce URI."))
|
||||
o.placeholder = "http://tracker.example.com/announce"
|
||||
end
|
||||
|
||||
s:tab("advance", translate("Advanced Options"))
|
||||
|
||||
o = s:taboption("advance", Flag, "disable_ipv6", translate("IPv6 disabled"),
|
||||
translate("Disable IPv6. This is useful if you have to use broken DNS and want to avoid terribly"
|
||||
.. " slow AAAA record lookup."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("advance", Value, "auto_save_interval", translate("Auto save interval"),
|
||||
translate("Save a control file (*.aria2) every N seconds. If 0 is given, a control file is not"
|
||||
.. " saved during download."))
|
||||
o.datatype = "range(0, 600)"
|
||||
o.placeholder = "60"
|
||||
|
||||
o = s:taboption("advance", Value, "save_session_interval", translate("Save session interval"),
|
||||
translate("Save error/unfinished downloads to session file every N seconds. If 0 is given, file"
|
||||
.. " will be saved only when aria2 exits."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("advance", Value, "disk_cache", translate("Disk cache"),
|
||||
"%s %s" % {
|
||||
translate("Enable disk cache (in bytes), set 0 to disabled."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "16M"
|
||||
|
||||
o = s:taboption("advance", ListValue, "file_allocation", translate("File allocation"),
|
||||
translate("Specify file allocation method. If you are using newer file systems such as ext4"
|
||||
.. " (with extents support), btrfs, xfs or NTFS (MinGW build only), \"falloc\" is your best choice."
|
||||
.. " It allocates large(few GiB) files almost instantly, but it may not be available if your system"
|
||||
.. " doesn't have posix_fallocate(3) function. Don't use \"falloc\" with legacy file systems such as"
|
||||
.. " ext3 and FAT32 because it takes almost same time as \"prealloc\" and it blocks aria2 entirely"
|
||||
.. " until allocation finishes."))
|
||||
o:value("none", translate("None"))
|
||||
o:value("prealloc", translate("prealloc"))
|
||||
o:value("trunc", translate("trunc"))
|
||||
o:value("falloc", translate("falloc"))
|
||||
o.default = "prealloc"
|
||||
|
||||
o = s:taboption("advance", Flag, "force_save", translate("Force save"),
|
||||
translate("Save download to session file even if the download is completed or removed."
|
||||
.. " This option also saves control file in that situations. This may be useful to save"
|
||||
.. " BitTorrent seeding which is recognized as completed state."))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.default = "false"
|
||||
|
||||
o = s:taboption("advance", Value, "max_overall_download_limit", translate("Max overall download limit"),
|
||||
"%s %s" % {
|
||||
translate("Set max overall download speed in bytes/sec. 0 means unrestricted."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:taboption("advance", Value, "max_download_limit", translate("Max download limit"),
|
||||
"%s %s" % {
|
||||
translate("Set max download speed per each download in bytes/sec. 0 means unrestricted."),
|
||||
translate("You can append K or M.")
|
||||
})
|
||||
o.placeholder = "0"
|
||||
|
||||
s = m:section(NamedSection, "main", "aria2", translate("Extra Settings"),
|
||||
translate("Settings in this section will be added to config file."))
|
||||
s.addremove = false
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(DynamicList, "extra_settings", translate("Settings list"),
|
||||
translate("List of extra settings. Format: option=value, eg. <code>netrc-path=/tmp/.netrc</code>."))
|
||||
o.placeholder = "option=value"
|
||||
|
||||
return m
|
|
@ -1,39 +0,0 @@
|
|||
-- Copyright 2017-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the MIT License.
|
||||
|
||||
local m, s, o
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local util = require "luci.util"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
local config_dir = uci:get("aria2", "main", "config_dir") or "/var/etc/aria2"
|
||||
local config_file = "%s/aria2.conf.main" % config_dir
|
||||
local session_file = "%s/aria2.session.main" % config_dir
|
||||
|
||||
m = SimpleForm("aria2", "%s - %s" % { translate("Aria2"), translate("Files") },
|
||||
translate("Here shows the files used by aria2."))
|
||||
m.reset = false
|
||||
m.submit = false
|
||||
|
||||
s = m:section(SimpleSection, nil, translatef("Content of config file: <code>%s</code>", config_file))
|
||||
|
||||
o = s:option(TextValue, "_config")
|
||||
o.rows = 20
|
||||
o.readonly = true
|
||||
o.cfgvalue = function()
|
||||
local v = fs.readfile(config_file) or translate("File does not exist.")
|
||||
return util.trim(v) ~= "" and v or translate("Empty file.")
|
||||
end
|
||||
|
||||
s = m:section(SimpleSection, nil, translatef("Content of session file: <code>%s</code>", session_file))
|
||||
|
||||
o = s:option(TextValue, "_session")
|
||||
o.rows = 20
|
||||
o.readonly = true
|
||||
o.cfgvalue = function()
|
||||
local v = fs.readfile(session_file) or translate("File does not exist.")
|
||||
return util.trim(v) ~= "" and v or translate("Empty file.")
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,55 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the MIT License.
|
||||
-%>
|
||||
|
||||
<% css = [[
|
||||
|
||||
#log_text {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
#log_text pre {
|
||||
word-break: break-all;
|
||||
margin: 0;
|
||||
}
|
||||
.description {
|
||||
background-color: #33ccff;
|
||||
}
|
||||
|
||||
]]
|
||||
-%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(10, '<%=url("admin/services/aria2/log/read")%>', null,
|
||||
function(x, data) {
|
||||
var logElm = document.getElementById('log_text');
|
||||
if (logElm) {
|
||||
logElm.innerHTML = data
|
||||
? String.format(
|
||||
'<pre>%s%s%s%s</pre>',
|
||||
'<span class="description"><%:Last 50 lines of log file:%></span><br/><br/>',
|
||||
data.log || '<%:No log data.%>',
|
||||
'<br/><br/><span class="description"><%:Last 50 lines of syslog:%></span><br/><br/>',
|
||||
data.syslog || '<%:No log data.%>'
|
||||
)
|
||||
: '<strong><%:Failed to load log data.%></strong>';
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]></script>
|
||||
<div class="cbi-map">
|
||||
<h2 name="content"><%:Aria2%> - <%:Log Data%></h2>
|
||||
<fieldset class="cbi-section">
|
||||
<div id="log_text">
|
||||
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" />
|
||||
<%:Collecting data...%>
|
||||
</div>
|
||||
<div style="text-align:right"><small><%:Refresh every 10 seconds.%></small></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
|
@ -1,116 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the MIT License.
|
||||
-%>
|
||||
|
||||
<%
|
||||
local ipkg = require "luci.model.ipkg"
|
||||
local has_ui = false
|
||||
|
||||
local uilist = {
|
||||
supported = {
|
||||
["ariang"] = "AriaNg",
|
||||
["webui-aria2"] = "WebUI-Aria2",
|
||||
["yaaw"] = "YAAW"
|
||||
},
|
||||
installed = {}
|
||||
}
|
||||
|
||||
for k in pairs(uilist.supported) do
|
||||
if ipkg.installed(k) then
|
||||
uilist.installed[#uilist.installed + 1] = k
|
||||
has_ui = true
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<p id="aria2_status">
|
||||
<em><%:Collecting data...%></em>
|
||||
</p>
|
||||
<% if has_ui then %>
|
||||
<p>
|
||||
<%:Installed web interface: %>
|
||||
<%- for _, v in pairs(uilist.installed) do %>
|
||||
<input type="button" class="cbi-button" style="margin: 0 5px;" value="<%=uilist.supported[v]%>" onclick="openWebInterface('<%=v%>');" />
|
||||
<%- end %>
|
||||
</p>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=url("admin/services/aria2/status")%>', null,
|
||||
function(x, data) {
|
||||
var tb = document.getElementById('aria2_status');
|
||||
if (data && tb) {
|
||||
tb.innerHTML = data.running
|
||||
? '<%:The Aria2 service is running.%>'
|
||||
: '<%:The Aria2 service is not running.%>';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function randomString(len) {
|
||||
var randomStr = '';
|
||||
var restLen = len;
|
||||
while ((restLen = len - randomStr.length) > 0) {
|
||||
randomStr += Math.random().toString(36).substring(2, 2 + restLen);
|
||||
}
|
||||
return randomStr;
|
||||
}
|
||||
|
||||
function randomToken() {
|
||||
var len = 32;
|
||||
var inputLength = prompt('<%:Please input token length:%>', len);
|
||||
if (inputLength === null || inputLength === '') {
|
||||
return;
|
||||
} else if (/^\d+$/.test(inputLength)) {
|
||||
len = parseInt(inputLength);
|
||||
}
|
||||
|
||||
var secretInput = document.getElementById('cbid.aria2.main.rpc_secret');
|
||||
if (secretInput) {
|
||||
secretInput.value = randomString(len);
|
||||
}
|
||||
};
|
||||
|
||||
function showRPCURL() {
|
||||
var portElm = document.getElementById('cbid.aria2.main.rpc_listen_port');
|
||||
var authMethodElm = document.getElementById('cbid.aria2.main.rpc_auth_method');
|
||||
var useWSElm = document.getElementById('cbid.aria2.main._use_ws');
|
||||
var secureElm = document.getElementById('cbid.aria2.main.rpc_secure');
|
||||
|
||||
var port = (portElm && /^\d+$/.test(portElm.value)) ? parseInt(portElm.value) : 6800;
|
||||
var authMethod = (authMethodElm && authMethodElm.value) ? authMethodElm.value : "none";
|
||||
var useWS = (useWSElm && useWSElm.checked) ? true : false;
|
||||
var secure = (secureElm && secureElm.checked) ? true : false;
|
||||
|
||||
var protocol = useWS
|
||||
? (secure ? 'wss' : 'ws')
|
||||
: (secure ? 'https' : 'http');
|
||||
var url = protocol + "://";
|
||||
|
||||
if (authMethod == 'token') {
|
||||
var authToken = document.getElementById('cbid.aria2.main.rpc_secret').value;
|
||||
url += 'token:' + authToken + '@';
|
||||
} else if (authMethod == 'user_pass') {
|
||||
var authUser = document.getElementById('cbid.aria2.main.rpc_user').value;
|
||||
var authPasswd = document.getElementById('cbid.aria2.main.rpc_passwd').value;
|
||||
url += authUser + ':' + authPasswd + '@';
|
||||
}
|
||||
url += window.location.hostname + ':' + port + '/jsonrpc';
|
||||
var rpcUrlElm = document.getElementById('cbid.aria2.main._rpc_url');
|
||||
|
||||
if (rpcUrlElm) {
|
||||
rpcUrlElm.value = url;
|
||||
} else {
|
||||
alert(url)
|
||||
}
|
||||
};
|
||||
|
||||
function openWebInterface(path) {
|
||||
var host = window.location.host;
|
||||
var protocol = window.location.protocol;
|
||||
window.open(protocol + '//' + host + '/' + path);
|
||||
};
|
||||
//]]></script>
|
|
@ -1,22 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2019 Xingwang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the MIT License.
|
||||
-%>
|
||||
|
||||
<%+cbi/valueheader%>
|
||||
<input data-update="change" type="text" class="cbi-input-text"<%=
|
||||
attr("id", cbid) ..
|
||||
attr("name", cbid) ..
|
||||
attr("value", self:cfgvalue(section) or self.default) ..
|
||||
ifattr(self.size, "size") ..
|
||||
ifattr(self.placeholder, "placeholder") ..
|
||||
ifattr(self.maxlength, "maxlength") ..
|
||||
ifattr(self.datatype, "data-type", self.datatype) ..
|
||||
ifattr(self.onmouseover, "onmouseover")
|
||||
%> />
|
||||
<%- if self.btntext then -%>
|
||||
<div class="cbi-button cbi-button-neutral" title="<%=self.btntext%>" aria-label="<%=self.btntext%>"<%=
|
||||
ifattr(self.btnclick, "onclick", self.btnclick)
|
||||
%>><span style="font-weight: normal;"><%=self.btntext%></span></div>
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ ."$(uci -q get aria2.main)" != ."aria2" ]; then
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
add aria2 aria2
|
||||
rename aria2.@aria2[-1]="main"
|
||||
set aria2.main.enabled=0
|
||||
set aria2.main.dir="/var/run/aria2"
|
||||
set aria2.main.config_dir="/var/etc/aria2"
|
||||
add_list aria2.main.header=""
|
||||
add_list aria2.main.bt_tracker=""
|
||||
add_list aria2.main.extra_settings=""
|
||||
commit aria2
|
||||
EOF
|
||||
fi
|
||||
|
||||
exit 0
|
25
applications/luci-app-aria2/root/usr/libexec/aria2-call
Executable file
25
applications/luci-app-aria2/root/usr/libexec/aria2-call
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/usr/share/libubox/jshn.sh"
|
||||
|
||||
action=$1
|
||||
shift
|
||||
|
||||
case "$action" in
|
||||
cat)
|
||||
case "$1" in
|
||||
conf|session)
|
||||
config_dir="$(uci -q get aria2.main.config_dir)"
|
||||
list_file="${config_dir:-/var/etc/aria2}/aria2.$1.main"
|
||||
json_init
|
||||
json_add_string file "$list_file"
|
||||
json_add_string content "$(cat "$list_file")"
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
tail)
|
||||
log_file=$(uci -q get aria2.main.log)
|
||||
tail -n 50 "${log_file:-/var/log/aria2.log}"
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"admin/services/aria2": {
|
||||
"title": "Aria2",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-aria2" ],
|
||||
"uci": { "aria2": true }
|
||||
}
|
||||
},
|
||||
|
||||
"admin/services/aria2/config": {
|
||||
"title": "Configuration",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "aria2/config"
|
||||
}
|
||||
},
|
||||
|
||||
"admin/services/aria2/files": {
|
||||
"title": "Files",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "aria2/files"
|
||||
}
|
||||
},
|
||||
|
||||
"admin/services/aria2/log": {
|
||||
"title": "Log",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "aria2/log"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,15 @@
|
|||
"luci-app-aria2": {
|
||||
"description": "Grant UCI access for luci-app-aria2",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"service": [ "list" ]
|
||||
},
|
||||
"file": {
|
||||
"/etc/passwd": [ "read" ],
|
||||
"/sbin/logread": [ "exec" ],
|
||||
"/usr/bin/aria2c": [ "exec" ],
|
||||
"/usr/libexec/aria2-call": [ "exec" ]
|
||||
},
|
||||
"uci": [ "aria2" ]
|
||||
},
|
||||
"write": {
|
||||
|
|
Loading…
Reference in a new issue