config.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. 'use strict';
  2. 'require dom';
  3. 'require form';
  4. 'require fs';
  5. 'require poll';
  6. 'require rpc';
  7. 'require tools.widgets as widgets';
  8. 'require ui';
  9. 'require view';
  10. var callServiceList, CBIAria2Status, CBIRpcSecret, CBIRpcUrl;
  11. callServiceList = rpc.declare({
  12. object: 'service',
  13. method: 'list',
  14. params: [ 'name' ],
  15. expect: { '': {} },
  16. filter: function (data, args, extra) {
  17. var i, res = data[args.name] || {};
  18. for (i = 0; (i < extra.length) && (Object.keys(res).length > 0); ++i)
  19. res = res[extra[i]] || {};
  20. return res;
  21. }
  22. });
  23. CBIAria2Status = form.DummyValue.extend({
  24. renderWidget: function() {
  25. var extra = ['instances', 'aria2.main'];
  26. var node = E('div', {}, E('p', {}, E('em', {}, _('Collecting data...'))));
  27. poll.add(function() {
  28. return Promise.all([
  29. callServiceList('aria2', extra)
  30. .then(function(res) {
  31. return E('p', {}, E('em', {}, res.running
  32. ? _('The Aria2 service is running.')
  33. : _('The Aria2 service is not running.'))
  34. );
  35. }),
  36. getWebFrontInstalled()
  37. .then(function(installed) {
  38. var btns = [E('label'), _('Installed web interface: ')];
  39. for (var i in installed) {
  40. btns.push(E('button', {
  41. 'class': 'btn cbi-button',
  42. 'click': openWebInterface.bind(this, i)
  43. }, installed[i]));
  44. }
  45. return btns.length > 0 ? E('p', btns) : null;
  46. })
  47. ]).then(function(res) {
  48. res = res.filter(function(r) { return r ? 1 : 0 });
  49. dom.content(node, res);
  50. });
  51. });
  52. return node;
  53. }
  54. });
  55. CBIRpcSecret = form.Value.extend({
  56. renderWidget: function(section_id, option_index, cfgvalue) {
  57. var node = this.super('renderWidget', [section_id, option_index, cfgvalue]);
  58. dom.append(node, [
  59. E('br'),
  60. E('span', { 'class': 'control-group' },
  61. E('button', {
  62. 'class': 'btn cbi-button cbi-button-neutral',
  63. 'click': this.clickFn.bind(this, section_id)
  64. }, this.btnTitle)
  65. )
  66. ]);
  67. return node;
  68. }
  69. });
  70. CBIRpcUrl = form.DummyValue.extend({
  71. renderWidget: function(section_id, option_index, cfgvalue) {
  72. var inputEl = new ui.Textfield('', {'id': this.cbid(section_id), 'readonly': true});
  73. return E([inputEl.render(),
  74. E('br'),
  75. E('span', { 'class': 'control-group' }, [
  76. E('button', {
  77. 'class': 'btn cbi-button cbi-button-neutral',
  78. 'click': this.clickFn.bind(this, section_id, 0, inputEl)
  79. }, 'HTTP(s)'),
  80. E('button', {
  81. 'class': 'btn cbi-button cbi-button-neutral',
  82. 'click': this.clickFn.bind(this, section_id, 1, inputEl)
  83. }, 'WebSocket(s)')
  84. ])
  85. ]);
  86. }
  87. });
  88. function getToken(section_id) {
  89. var len = 32, randomStr = '';
  90. var inputLength = prompt(_('Please input token length:'), len);
  91. if (inputLength === null || inputLength === '') {
  92. return;
  93. } else if (/^\d+$/.test(inputLength)) {
  94. len = parseInt(inputLength);
  95. }
  96. while(len - randomStr.length > 0) {
  97. randomStr += Math.random().toString(36).substring(2, 2 + len - randomStr.length);
  98. }
  99. document.getElementById('widget.' + this.cbid(section_id)).value = randomStr;
  100. };
  101. function getWebFrontInstalled() {
  102. var supported = {'ariang': 'AriaNg', 'webui-aria2': 'WebUI-Aria2', 'yaaw': 'YAAW'};
  103. var actions = [];
  104. for (var s in supported) {
  105. actions.push(fs.stat('/www/' + s + '/index.html')
  106. .then(L.bind(function(s) { return s; }, this, s))
  107. .catch(function(err) { return null; }));
  108. }
  109. return Promise.all(actions).then(function(res) {
  110. var installed = {};
  111. for (var i = 0; i < res.length; ++i)
  112. if (res[i])
  113. installed[res[i]] = supported[res[i]];
  114. return installed;
  115. });
  116. }
  117. function openWebInterface(path) {
  118. var host = window.location.host;
  119. var protocol = window.location.protocol;
  120. window.open(protocol + '//' + host + '/' + path);
  121. };
  122. function showRPCURL(section_id, useWS, inputEl) {
  123. var getOptVal = L.bind(function(opt, default_val) {
  124. default_val = default_val || null;
  125. return this.section.formvalue(section_id, opt) || default_val;
  126. }, this);
  127. var port = getOptVal('rpc_listen_port', 6800);
  128. var authMethod = getOptVal('rpc_auth_method', 'none');
  129. var secure = JSON.parse(getOptVal('rpc_secure', false));
  130. var protocol = useWS
  131. ? (secure ? 'wss' : 'ws')
  132. : (secure ? 'https' : 'http');
  133. var url = protocol + '://';
  134. if (authMethod == 'token') {
  135. var authToken = getOptVal('rpc_secret');
  136. if (authToken)
  137. url += 'token:' + authToken + '@';
  138. } else if (authMethod == 'user_pass') {
  139. var authUser = getOptVal('rpc_user');
  140. var authPasswd = getOptVal('rpc_passwd');
  141. if (authUser && authPasswd)
  142. url += authUser + ':' + authPasswd + '@';
  143. }
  144. url += window.location.hostname + ':' + port + '/jsonrpc';
  145. inputEl.setValue(url);
  146. };
  147. return view.extend({
  148. load: function() {
  149. return fs.exec_direct('/usr/bin/aria2c', [ '-v' ]).then(function(res) {
  150. var info = {}, lines = res.split(/\r?\n|\r/g);
  151. for (var i = 0; i < lines.length; ++i) {
  152. if (/^aria2 version/.exec(lines[i])) {
  153. info.version = lines[i].match(/(\d+\.){2}\d+/)[0];
  154. }
  155. else if (/^Enabled Features/.exec(lines[i])) {
  156. info.gzip = lines[i].search(/GZip/) >= 0;
  157. info.https = lines[i].search(/HTTPS/) >= 0;
  158. info.bt = lines[i].search(/BitTorrent/) >= 0;
  159. info.sftp = lines[i].search(/SFTP/) >= 0;
  160. info.adns = lines[i].search(/Async DNS/) >= 0;
  161. info.cookie = lines[i].search(/Firefox3 Cookie/) >= 0;
  162. }
  163. }
  164. return info;
  165. });
  166. },
  167. render: function(aria2) {
  168. var m, s, o;
  169. m = new form.Map('aria2', '%s - %s'.format(_('Aria2'), _('Settings')), '<p>%s</p><p>%s</p>'.format(
  170. _('Aria2 is a lightweight multi-protocol &amp; multi-source, cross platform download utility.'),
  171. _('For more information, please visit: %s.')
  172. .format('<a href="https://aria2.github.io" target="_blank">https://aria2.github.io</a>')));
  173. s = m.section(form.TypedSection);
  174. s.title = '%s - %s'.format(_('Aria2'), _('Running Status'));
  175. s.anonymous = true;
  176. s.cfgsections = function() { return [ 'status' ] };
  177. o = s.option(CBIAria2Status);
  178. s = m.section(form.NamedSection, 'main', 'aria2');
  179. s.addremove = false;
  180. s.anonymous = true;
  181. s.tab('basic', _('Basic Options'));
  182. o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'));
  183. o.rmempty = false;
  184. o = s.taboption('basic', widgets.UserSelect, 'user', _('Run daemon as user'),
  185. _('Leave blank to use default user.'));
  186. o = s.taboption('basic', form.Value, 'dir', _('Download directory'),
  187. _('The directory to store the downloaded file. For example <code>/mnt/sda1</code>.'));
  188. o.rmempty = false;
  189. o = s.taboption('basic', form.Value, 'config_dir', _('Config file directory'),
  190. _('The directory to store the config file, session file and DHT file.'));
  191. o.placeholder = '/var/etc/aria2';
  192. o = s.taboption('basic', form.Flag, 'enable_logging', _('Enable logging'));
  193. o.rmempty = false;
  194. o = s.taboption('basic', form.Value, 'log', _('Log file'),
  195. _('The file name of the log file.'));
  196. o.depends('enable_logging', '1');
  197. o.placeholder = '/var/log/aria2.log';
  198. o = s.taboption('basic', form.ListValue, 'log_level', _('Log level'));
  199. o.depends('enable_logging', '1');
  200. o.value('debug', _('Debug'));
  201. o.value('info', _('Info'));
  202. o.value('notice', _('Notice'));
  203. o.value('warn', _('Warn'));
  204. o.value('error', _('Error'));
  205. o.default = 'warn';
  206. o = s.taboption('basic', form.Value, 'max_concurrent_downloads', _('Max concurrent downloads'));
  207. o.placeholder = '5';
  208. s.tab('rpc', _('RPC Options'))
  209. o = s.taboption('rpc', form.Flag, 'pause', _('Pause'), _('Pause download after added.'));
  210. o.enabled = 'true';
  211. o.disabled = 'false';
  212. o.default = 'false';
  213. o = s.taboption('rpc', form.Flag, 'pause_metadata', _('Pause metadata'),
  214. _('Pause downloads created as a result of metadata download.'));
  215. o.enabled = 'true';
  216. o.disabled = 'false';
  217. o.default = 'false';
  218. o = s.taboption('rpc', form.Value, 'rpc_listen_port', _('RPC port'));
  219. o.datatype = 'range(1024,65535)';
  220. o.placeholder = '6800';
  221. o = s.taboption('rpc', form.ListValue, 'rpc_auth_method', _('RPC authentication method'));
  222. o.value('none', _('No Authentication'));
  223. o.value('user_pass', _('Username & Password'));
  224. o.value('token', _('Token'));
  225. o = s.taboption('rpc', form.Value, 'rpc_user', _('RPC username'));
  226. o.depends('rpc_auth_method', 'user_pass');
  227. o = s.taboption('rpc', form.Value, 'rpc_passwd', _('RPC password'));
  228. o.depends('rpc_auth_method', 'user_pass');
  229. o.password = true;
  230. o = s.taboption('rpc', CBIRpcSecret, 'rpc_secret', _('RPC token'));
  231. o.depends('rpc_auth_method', 'token');
  232. o.btnTitle = _('Generate Randomly');
  233. o.clickFn = getToken;
  234. o.password = true;
  235. if (aria2.https) {
  236. o = s.taboption('rpc', form.Flag, 'rpc_secure', _('RPC secure'),
  237. _('RPC transport will be encrypted by SSL/TLS. The RPC clients must use https'
  238. + ' scheme to access the server. For WebSocket client, use wss scheme.'));
  239. o.enabled = 'true';
  240. o.disabled = 'false';
  241. o.rmempty = false;
  242. o = s.taboption('rpc', form.Value, 'rpc_certificate', _('RPC certificate'),
  243. _('Use the certificate in FILE for RPC server. The certificate must be either'
  244. + ' in PKCS12 (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the'
  245. + ' certificate, a key and optionally a chain of additional certificates. Only PKCS12'
  246. + ' files with a blank import password can be opened!<br/>When using PEM, you have to'
  247. + ' specify the "RPC private key" as well.'));
  248. o.depends('rpc_secure', 'true');
  249. o.optional = false;
  250. o.rmempty = false;
  251. o = s.taboption('rpc', form.Value, 'rpc_private_key', _('RPC private key'),
  252. _('Use the private key in FILE for RPC server. The private key must be'
  253. + ' decrypted and in PEM format.'));
  254. o.depends('rpc_secure', 'true');
  255. o.optional = false;
  256. o.rmempty = false;
  257. }
  258. o = s.taboption('rpc', CBIRpcUrl, '_rpc_url', _('Json-RPC URL'));
  259. o.clickFn = showRPCURL;
  260. s.tab('http', _('HTTP/FTP/SFTP Options'));
  261. o = s.taboption('http', form.Flag, 'enable_proxy', _('Enable proxy'));
  262. o.rmempty = false;
  263. o = s.taboption('http', form.Value, 'all_proxy', _('All proxy'),
  264. _('Use a proxy server for all protocols.'));
  265. o.depends('enable_proxy', '1');
  266. o.placeholder = '[http://][USER:PASSWORD@]HOST[:PORT]';
  267. o = s.taboption('http', form.Value, 'all_proxy_user', _('Proxy user'));
  268. o.depends('enable_proxy', '1');
  269. o = s.taboption('http', form.Value, 'all_proxy_passwd', _('Proxy password'));
  270. o.depends('enable_proxy', '1');
  271. o.password = true;
  272. if (aria2.https) {
  273. o = s.taboption('http', form.Flag, 'check_certificate', _('Check certificate'),
  274. _('Verify the peer using certificates specified in "CA certificate" option.'));
  275. o.enabled = 'true';
  276. o.disabled = 'false';
  277. o.default = 'true';
  278. o.rmempty = false;
  279. o = s.taboption('http', form.Value, 'ca_certificate', _('CA certificate'),
  280. _('Use the certificate authorities in FILE to verify the peers. The certificate'
  281. + ' file must be in PEM format and can contain multiple CA certificates.'));
  282. o.depends('check_certificate', 'true');
  283. o = s.taboption('http', form.Value, 'certificate', _('Certificate'),
  284. _('Use the client certificate in FILE. The certificate must be either in PKCS12'
  285. + ' (.p12, .pfx) or in PEM format.<br/>PKCS12 files must contain the certificate, a'
  286. + ' key and optionally a chain of additional certificates. Only PKCS12 files with a'
  287. + ' blank import password can be opened!<br/>When using PEM, you have to specify the'
  288. + ' "Private key" as well.'));
  289. o = s.taboption('http', form.Value, 'private_key', _('Private key'),
  290. _('Use the private key in FILE. The private key must be decrypted and in PEM'
  291. + ' format. The behavior when encrypted one is given is undefined.'));
  292. }
  293. if (aria2.gzip) {
  294. o = s.taboption('http', form.Flag, 'http_accept_gzip', _('HTTP accept gzip'),
  295. _('Send <code>Accept: deflate, gzip</code> request header and inflate response'
  296. + ' if remote server responds with <code>Content-Encoding: gzip</code> or'
  297. + ' <code>Content-Encoding: deflate</code>.'));
  298. o.enabled = 'true';
  299. o.disabled = 'false';
  300. o.default = 'false';
  301. }
  302. o = s.taboption('http', form.Flag, 'http_no_cache', _('HTTP no cache'),
  303. _('Send <code>Cache-Control: no-cache</code> and <code>Pragma: no-cache</code>'
  304. + ' header to avoid cached content. If disabled, these headers are not sent and you'
  305. + ' can add Cache-Control header with a directive you like using "Header" option.'));
  306. o.enabled = 'true';
  307. o.disabled = 'false';
  308. o.default = 'false';
  309. o = s.taboption('http', form.DynamicList, 'header', _('Header'),
  310. _('Append HEADERs to HTTP request header.'));
  311. o = s.taboption('http', form.Value, 'connect_timeout', _('Connect timeout'),
  312. _('Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server.' +
  313. ' After the connection is established, this option makes no effect and "Timeout" option is used instead.'));
  314. o.datatype = 'uinteger';
  315. o.placeholder = '60';
  316. o = s.taboption('http', form.Value, 'timeout', _('Timeout'));
  317. o.datatype = 'uinteger';
  318. o.placeholder = '60';
  319. o = s.taboption('http', form.Value, 'lowest_speed_limit', _('Lowest speed limit'),
  320. '%s %s'.format(
  321. _('Close connection if download speed is lower than or equal to this value (bytes per sec). ' +
  322. '0 means has no lowest speed limit.'),
  323. _('You can append K or M.')
  324. ));
  325. o.placeholder = '0';
  326. o = s.taboption('http', form.Value, 'max_connection_per_server', _('Max connection per server'),
  327. _('The maximum number of connections to one server for each download.'));
  328. o.datatype = 'uinteger';
  329. o.placeholder = '1';
  330. o = s.taboption('http', form.Value, 'split', _('Max number of split'),
  331. _('Download a file using N connections.'));
  332. o.datatype = 'uinteger';
  333. o.placeholder = '5';
  334. o = s.taboption('http', form.Value, 'min_split_size', _('Min split size'),
  335. _('Don\'t split less than 2*SIZE byte range. Possible values: 1M-1024M.'));
  336. o.placeholder = '20M';
  337. o = s.taboption('http', form.Value, 'max_tries', _('Max tries'));
  338. o.datatype = 'uinteger';
  339. o.placeholder = '5';
  340. o = s.taboption('http', form.Value, 'retry_wait', _('Retry wait'),
  341. _('Set the seconds to wait between retries.'));
  342. o.datatype = 'uinteger';
  343. o.placeholder = '0';
  344. o = s.taboption('http', form.Value, 'user_agent', _('User agent'),
  345. _('Set user agent for HTTP(S) downloads.'));
  346. o.placeholder = 'aria2/%s'.format(aria2.version ? aria2.version : '$VERSION');
  347. if (aria2.bt) {
  348. s.tab('bt', _('BitTorrent Options'));
  349. o = s.taboption('bt', form.Flag, 'enable_dht', _('IPv4 <abbr title="Distributed Hash Table">DHT</abbr> enabled'),
  350. '%s %s'.format(
  351. _('Enable IPv4 DHT functionality. It also enables UDP tracker support.'),
  352. _('This option will be ignored if a private flag is set in a torrent.')
  353. ));
  354. o.enabled = 'true';
  355. o.disabled = 'false';
  356. o.default = 'true';
  357. o.rmempty = false;
  358. o = s.taboption('bt', form.Flag, 'enable_dht6', _('IPv6 <abbr title="Distributed Hash Table">DHT</abbr> enabled'),
  359. '%s %s'.format(
  360. _('Enable IPv6 DHT functionality.'),
  361. _('This option will be ignored if a private flag is set in a torrent.')
  362. ));
  363. o.enabled = 'true';
  364. o.disabled = 'false';
  365. o = s.taboption('bt', form.Flag, 'bt_enable_lpd', _('<abbr title="Local Peer Discovery">LPD</abbr> enabled'),
  366. '%s %s'.format(
  367. _('Enable Local Peer Discovery.'),
  368. _('This option will be ignored if a private flag is set in a torrent.')
  369. ));
  370. o.enabled = 'true';
  371. o.disabled = 'false';
  372. o.default = 'false';
  373. o = s.taboption('bt', form.Flag, 'enable_peer_exchange', _('Enable peer exchange'),
  374. '%s %s'.format(
  375. _('Enable Peer Exchange extension.'),
  376. _('This option will be ignored if a private flag is set in a torrent.')
  377. ));
  378. o.enabled = 'true';
  379. o.disabled = 'false';
  380. o.default = 'true';
  381. o.rmempty = false;
  382. o = s.taboption('bt', form.Flag, 'bt_save_metadata', _('Save metadata'),
  383. _('Save meta data as ".torrent" file. This option has effect only when BitTorrent'
  384. + ' Magnet URI is used. The file name is hex encoded info hash with suffix ".torrent".'));
  385. o.enabled = 'true';
  386. o.disabled = 'false';
  387. o.default = 'false';
  388. o = s.taboption('bt', form.Flag, 'bt_remove_unselected_file', _('Remove unselected file'),
  389. _('Removes the unselected files when download is completed in BitTorrent. Please'
  390. + ' use this option with care because it will actually remove files from your disk.'));
  391. o.enabled = 'true';
  392. o.disabled = 'false';
  393. o.default = 'false';
  394. o = s.taboption('bt', form.Flag, 'bt_seed_unverified', _('Seed unverified'),
  395. _('Seed previously downloaded files without verifying piece hashes.'));
  396. o.enabled = 'true';
  397. o.disabled = 'false';
  398. o.default = 'false';
  399. o = s.taboption('bt', form.Value, 'listen_port', _('BitTorrent listen port'),
  400. _('Set TCP port number for BitTorrent downloads. Accept format: "6881,6885",'
  401. + ' "6881-6999" and "6881-6889,6999". Make sure that the specified ports are open'
  402. + ' for incoming TCP traffic.'));
  403. o.placeholder = '6881-6999';
  404. o = s.taboption('bt', form.Value, 'dht_listen_port', _('DHT Listen port'),
  405. _('Set UDP listening port used by DHT (IPv4, IPv6) and UDP tracker. Make sure that the '
  406. + 'specified ports are open for incoming UDP traffic.'));
  407. o.depends('enable_dht', 'true');
  408. o.depends('enable_dht6', 'true');
  409. o.placeholder = '6881-6999';
  410. o = s.taboption('bt', form.ListValue, 'follow_torrent', _('Follow torrent'));
  411. o.value('true', _('True'));
  412. o.value('false', _('False'));
  413. o.value('mem', _('Keep in memory'));
  414. o = s.taboption('bt', form.Value, 'max_overall_upload_limit', _('Max overall upload limit'),
  415. '%s %s'.format(
  416. _('Set max overall upload speed in bytes/sec. 0 means unrestricted.'),
  417. _('You can append K or M.')
  418. ));
  419. o.placeholder = '0';
  420. o = s.taboption('bt', form.Value, 'max_upload_limit', _('Max upload limit'),
  421. '%s %s'.format(
  422. _('Set max upload speed per each torrent in bytes/sec. 0 means unrestricted.'),
  423. _('You can append K or M.')
  424. ));
  425. o.placeholder = '0';
  426. o = s.taboption('bt', form.Value, 'bt_max_open_files', _('Max open files'),
  427. _('Specify maximum number of files to open in multi-file BitTorrent download globally.'));
  428. o.datatype = 'uinteger';
  429. o.placeholder = '100';
  430. o = s.taboption('bt', form.Value, 'bt_max_peers', _('Max peers'),
  431. _('Specify the maximum number of peers per torrent, 0 means unlimited.'));
  432. o.datatype = 'uinteger';
  433. o.placeholder = '55';
  434. o = s.taboption('bt', form.Value, 'bt_request_peer_speed_limit', _('Request peer speed limit'),
  435. '%s %s'.format(
  436. _('If the whole download speed of every torrent is lower than SPEED, aria2'
  437. + ' temporarily increases the number of peers to try for more download speed.'
  438. + ' Configuring this option with your preferred download speed can increase your'
  439. + ' download speed in some cases.'),
  440. _('You can append K or M.')
  441. ));
  442. o.placeholder = '50K';
  443. o = s.taboption('bt', form.Value, 'bt_stop_timeout', _('Stop timeout'),
  444. _('Stop BitTorrent download if download speed is 0 in consecutive N seconds. If 0 is'
  445. + ' given, this feature is disabled.'));
  446. o.datatype = 'uinteger';
  447. o.placeholder = '0';
  448. o = s.taboption('bt', form.Value, 'peer_id_prefix', _('Prefix of peer ID'),
  449. _('Specify the prefix of peer ID. The peer ID in BitTorrent is 20 byte length.'
  450. + ' If more than 20 bytes are specified, only first 20 bytes are used. If less than 20'
  451. + ' bytes are specified, random byte data are added to make its length 20 bytes.'));
  452. o.placeholder = 'A2-%s-'.format(
  453. aria2.version ? aria2.version.replace(/\./g, '-') : '$MAJOR-$MINOR-$PATCH'
  454. );
  455. o = s.taboption('bt', form.Value, 'seed_ratio', _('Seed ratio'),
  456. _('Specify share ratio. Seed completed torrents until share ratio reaches RATIO.'
  457. + ' You are strongly encouraged to specify equals or more than 1.0 here. Specify 0.0 if'
  458. + ' you intend to do seeding regardless of share ratio.'));
  459. o.datatype = 'ufloat';
  460. o.placeholder = '1.0';
  461. o = s.taboption('bt', form.Value, 'seed_time', _('Seed time'),
  462. _('Specify seeding time in minutes. If "Seed ratio" option is'
  463. + ' specified along with this option, seeding ends when at least one of the conditions'
  464. + ' is satisfied. Specifying 0 disables seeding after download completed.'));
  465. o.datatype = 'ufloat';
  466. o = s.taboption('bt', form.DynamicList, 'bt_tracker', _('Additional BT tracker'),
  467. _('List of additional BitTorrent tracker\'s announce URI.'));
  468. o.placeholder = 'http://tracker.example.com/announce';
  469. }
  470. s.tab('advance', _('Advanced Options'));
  471. o = s.taboption('advance', form.Flag, 'disable_ipv6', _('IPv6 disabled'),
  472. _('Disable IPv6. This is useful if you have to use broken DNS and want to avoid terribly'
  473. + ' slow AAAA record lookup.'));
  474. o.enabled = 'true';
  475. o.disabled = 'false';
  476. o.default = 'false';
  477. o = s.taboption('advance', form.Value, 'auto_save_interval', _('Auto save interval'),
  478. _('Save a control file (*.aria2) every N seconds. If 0 is given, a control file is not'
  479. + ' saved during download.'));
  480. o.datatype = 'range(0, 600)';
  481. o.placeholder = '60';
  482. o = s.taboption('advance', form.Value, 'save_session_interval', _('Save session interval'),
  483. _('Save error/unfinished downloads to session file every N seconds. If 0 is given, file'
  484. + ' will be saved only when aria2 exits.'));
  485. o.datatype = 'uinteger';
  486. o.placeholder = '0';
  487. o = s.taboption('advance', form.Value, 'disk_cache', _('Disk cache'),
  488. '%s %s'.format(
  489. _('Enable disk cache (in bytes), set 0 to disabled.'),
  490. _('You can append K or M.')
  491. ));
  492. o.placeholder = '16M';
  493. o = s.taboption('advance', form.ListValue, 'file_allocation', _('File allocation'),
  494. _('Specify file allocation method. If you are using newer file systems such as ext4'
  495. + ' (with extents support), btrfs, xfs or NTFS (MinGW build only), "falloc" is your best choice.'
  496. + ' It allocates large(few GiB) files almost instantly, but it may not be available if your system'
  497. + ' doesn\'t have posix_fallocate(3) function. Don\'t use "falloc" with legacy file systems such as'
  498. + ' ext3 and FAT32 because it takes almost same time as "prealloc" and it blocks aria2 entirely'
  499. + ' until allocation finishes.'));
  500. o.value('none', _('None'));
  501. o.value('prealloc', _('prealloc'));
  502. o.value('trunc', _('trunc'));
  503. o.value('falloc', _('falloc'));
  504. o.default = 'prealloc';
  505. o = s.taboption('advance', form.Flag, 'force_save', _('Force save'),
  506. _('Save download to session file even if the download is completed or removed.'
  507. + ' This option also saves control file in that situations. This may be useful to save'
  508. + ' BitTorrent seeding which is recognized as completed state.'));
  509. o.enabled = 'true';
  510. o.disabled = 'false';
  511. o.default = 'false';
  512. o = s.taboption('advance', form.Value, 'max_overall_download_limit', _('Max overall download limit'),
  513. '%s %s'.format(
  514. _('Set max overall download speed in bytes/sec. 0 means unrestricted.'),
  515. _('You can append K or M.')
  516. ));
  517. o.placeholder = '0';
  518. o = s.taboption('advance', form.Value, 'max_download_limit', _('Max download limit'),
  519. '%s %s'.format(
  520. _('Set max download speed per each download in bytes/sec. 0 means unrestricted.'),
  521. _('You can append K or M.')
  522. ));
  523. o.placeholder = '0';
  524. s = m.section(form.NamedSection, 'main', 'aria2', _('Extra Settings'),
  525. _('Settings in this section will be added to config file.'));
  526. s.addremove = false;
  527. s.anonymous = true;
  528. o = s.option(form.DynamicList, 'extra_settings', _('Settings list'),
  529. _('List of extra settings. Format: option=value, eg. <code>netrc-path=/tmp/.netrc</code>.'));
  530. o.placeholder = 'option=value';
  531. return m.render();
  532. }
  533. });