status.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* SPDX-License-Identifier: GPL-3.0-only
  2. *
  3. * Copyright (C) 2022 ImmortalWrt.org
  4. */
  5. 'use strict';
  6. 'require dom';
  7. 'require form';
  8. 'require fs';
  9. 'require poll';
  10. 'require rpc';
  11. 'require ui';
  12. 'require view';
  13. return view.extend({
  14. render: function() {
  15. var m, s, o;
  16. var unm_helper = '/usr/share/unblockneteasemusic/update.sh';
  17. m = new form.Map('unblockneteasemusic');
  18. s = m.section(form.NamedSection, 'config', 'unblockneteasemusic', _('核心管理'));
  19. s.anonymous = true;
  20. o = s.option(form.DummyValue, '_core_version', _('核心版本'));
  21. o.cfgvalue = function() {
  22. var _this = this;
  23. var spanTemp = '<div style="color:%s;margin-top:5px;"><strong>%s</strong></div>';
  24. return fs.exec(unm_helper, [ 'check_version' ]).then(function(res) {
  25. if (res.code === 0)
  26. _this.default = String.format(spanTemp, 'green', res.stdout.trim());
  27. else if (res.code === 2)
  28. _this.default = String.format(spanTemp, 'red', _('未安装'));
  29. else {
  30. ui.addNotification(null, E('p', [ _('获取版本信息失败:%s。').format(res) ]));
  31. _this.default = String.format(spanTemp, 'red', _('未知错误'));
  32. }
  33. return null;
  34. }).catch(function(err) {
  35. ui.addNotification(null, E('p', [ _('未知错误:%s。').format(err) ]));
  36. _this.default = String.format(spanTemp, 'red', _('未知错误'));
  37. return null;
  38. });
  39. }
  40. o.rawhtml = true;
  41. o = s.option(form.Button, '_remove_core', _('删除核心'),
  42. _('删除核心后,需手动点击下面的按钮重新下载,有助于解决版本冲突问题。'));
  43. o.inputstyle = 'remove';
  44. o.onclick = function() {
  45. var _this = this;
  46. return fs.exec(unm_helper, [ 'remove_core' ]).then(function(res) {
  47. _this.description = '删除完毕。'
  48. return _this.map.reset();
  49. }).catch(function(err) {
  50. ui.addNotification(null, E('p', [ _('未知错误:%s。').format(err) ]));
  51. _this.description = '删除失败。'
  52. return _this.map.reset();
  53. });
  54. }
  55. o = s.option(form.Button, '_update_core', _('更新核心'),
  56. _('更新完毕后会自动在后台重启插件,无需手动重启。'));
  57. o.inputstyle = 'action';
  58. o.onclick = function() {
  59. var _this = this;
  60. return fs.exec(unm_helper, [ 'update_core' ]).then(function (res) {
  61. if (res.code === 0)
  62. _this.description = _('更新成功。');
  63. else if (res.code === 1)
  64. _this.description = _('更新失败。');
  65. else if (res.code === 2)
  66. _this.description = _('更新程序正在运行中。');
  67. else if (res.code === 3)
  68. _this.description = _('当前已是最新版本。');
  69. return _this.map.reset();
  70. }).catch(function (err) {
  71. ui.addNotification(null, E('p', [ _('未知错误:%s。').format(err) ]));
  72. _this.description = _('更新失败。');
  73. return _this.map.reset();
  74. });
  75. }
  76. o = s.option(form.Button, '_debug_log', _('调试报告'),
  77. _('若您遇到使用上的问题,请点此打印调试报告,并将其附在您的 issue 中。'));
  78. o.inputstyle = 'action';
  79. o.inputtitle = _('打印报告');
  80. o.onclick = function() {
  81. var log_modal = ui.showModal(_('打印调试报告'), [
  82. E('p', { 'class': 'spinning' },
  83. _('正在打印调试报告中...'))
  84. ]);
  85. return fs.exec_direct('/usr/bin/unm-debug', 'text').then(function (res) {
  86. log_modal.removeChild(log_modal.lastChild);
  87. if (res) {
  88. log_modal.appendChild(E('p', _('提交 issue 时,您只需附上最后的链接,无需提供整个输出。')));
  89. log_modal.appendChild(E('textarea', {
  90. 'id': 'content_debugLog',
  91. 'class': 'cbi-input-textarea',
  92. 'style': 'font-size:13px; resize: none',
  93. 'readonly': 'readonly',
  94. 'wrap': 'soft',
  95. 'rows': '30'
  96. }, [ res.trim() ])
  97. );
  98. } else {
  99. log_modal.appendChild(E('p', _('错误')));
  100. log_modal.appendChild(E('pre', { 'class': 'errors' }, [ _('无法打印调试报告。') ]));
  101. }
  102. var log_element = document.getElementById('content_debugLog') || null;
  103. if (log_element)
  104. log_element.scrollTop = log_element.scrollHeight;
  105. log_modal.appendChild(E('div', { 'class': 'right' }, [
  106. log_element ? E('button', {
  107. 'class': 'btn cbi-button-action',
  108. 'click': ui.createHandlerFn(this, function() {
  109. var links = log_element.value.match(/https:\/\/(litter.catbox.moe|transfer.sh)\/.*.txt/g);
  110. var textarea = document.createElement('textarea');
  111. document.body.appendChild(textarea);
  112. textarea.style.position = 'absolute';
  113. textarea.style.clip = 'rect(0 0 0 0)';
  114. textarea.value = links ? links.join('\n'): log_element.value;
  115. textarea.select()
  116. document.execCommand('copy', true);
  117. document.body.removeChild(textarea);
  118. })
  119. }, _('复制')) : '',
  120. E('button', {
  121. 'class': 'btn',
  122. 'click': ui.hideModal
  123. }, _('关闭'))
  124. ]));
  125. return null;
  126. }).catch(function (err) {
  127. ui.addNotification(null, E('p', _('无法打印调试报告:%s。').format(err)));
  128. ui.hideModal();
  129. return null;
  130. });
  131. }
  132. o = s.option(form.DummyValue, '_logview');
  133. o.render = function() {
  134. /* Thanks to luci-app-aria2 */
  135. var css = ' \
  136. #log_textarea { \
  137. padding: 10px; \
  138. text-align: left; \
  139. } \
  140. #log_textarea pre { \
  141. padding: .5rem; \
  142. word-break: break-all; \
  143. margin: 0; \
  144. } \
  145. .description { \
  146. background-color: #33ccff; \
  147. }';
  148. var log_textarea = E('div', { 'id': 'log_textarea' },
  149. E('img', {
  150. 'src': L.resource('icons/loading.gif'),
  151. 'alt': _('Loading'),
  152. 'style': 'vertical-align:middle'
  153. }, _('Collecting data...'))
  154. );
  155. poll.add(L.bind(function() {
  156. return fs.read('/var/run/unblockneteasemusic/run.log', 'text')
  157. .then(function(res) {
  158. var log = E('pre', { 'wrap': 'pre' }, [
  159. res.trim() || _('当前无日志。')
  160. ]);
  161. dom.content(log_textarea, log);
  162. }).catch(function(err) {
  163. if (err.toString().includes('NotFoundError'))
  164. var log = E('pre', { 'wrap': 'pre' }, [
  165. _('日志文件不存在。')
  166. ]);
  167. else
  168. var log = E('pre', { 'wrap': 'pre' }, [
  169. _('未知错误:%s。').format(err)
  170. ]);
  171. dom.content(log_textarea, log);
  172. });
  173. }));
  174. return E([
  175. E('style', [ css ]),
  176. E('div', {'class': 'cbi-map'}, [
  177. E('h3', {'name': 'content'}, _('运行日志')),
  178. E('div', {'class': 'cbi-section'}, [
  179. log_textarea,
  180. E('div', {'style': 'text-align:right'},
  181. E('small', {}, _('每 %s 秒刷新。').format(L.env.pollinterval))
  182. )
  183. ])
  184. ])
  185. ]);
  186. }
  187. return m.render();
  188. },
  189. handleSaveApply: null,
  190. handleSave: null,
  191. handleReset: null
  192. });