Skip to content

Commit

Permalink
luci-app-alist: rewritten in JS
Browse files Browse the repository at this point in the history
Signed-off-by: sbwml <admin@cooluc.com>
  • Loading branch information
sbwml committed Aug 14, 2024
1 parent d07184f commit 7f3cdca
Show file tree
Hide file tree
Showing 14 changed files with 330 additions and 280 deletions.
12 changes: 2 additions & 10 deletions luci-app-alist/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=luci-app-alist
PKG_VERSION:=1.0.13
PKG_VERSION:=1.1.0
PKG_RELEASE:=1

LUCI_TITLE:=LuCI support for alist
LUCI_DEPENDS:=+alist +luci-compat

define Package/$(PKG_NAME)/postinst
#!/bin/sh
[ -n "${IPKG_INSTROOT}" ] || {
( . /etc/uci-defaults/50-luci-alist ) && rm -f /etc/uci-defaults/50-luci-alist
exit 0
}
endef
LUCI_DEPENDS:=+alist

include $(TOPDIR)/feeds/luci/luci.mk

Expand Down
199 changes: 199 additions & 0 deletions luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
'use strict';
'require form';
'require fs';
'require poll';
'require rpc';
'require uci';
'require view';

var callServiceList = rpc.declare({
object: 'service',
method: 'list',
params: ['name'],
expect: { '': {} }
});

function getServiceStatus() {
return L.resolveDefault(callServiceList('alist'), {}).then(function (res) {
var isRunning = false;
try {
isRunning = res['alist']['instances']['alist']['running'];
} catch (e) { }
return isRunning;
});
}

function renderStatus(isRunning, protocol, webport) {
var spanTemp = '<em><span style="color:%s"><strong>%s %s</strong></span></em>';
var renderHTML;
if (isRunning) {
var button = String.format('<input class="cbi-button-reload" type="button" style="margin-left: 50px" value="%s" onclick="window.open(\'%s//%s:%s/\')">',
_('Open Web Interface'), protocol, window.location.hostname, webport);
renderHTML = spanTemp.format('green', 'Alist', _('RUNNING')) + button;
} else {
renderHTML = spanTemp.format('red', 'Alist', _('NOT RUNNING'));
}

return renderHTML;
}

return view.extend({
load: function () {
return Promise.all([
uci.load('alist')
]);
},

handleResetPassword: async function (data) {
var data_dir = uci.get(data[0], '@alist[0]', 'data_dir') || '/etc/alist';
try {
var newpassword = await fs.exec('/usr/bin/alist', ['admin', 'random', '--data', data_dir]);
var new_password = newpassword.stderr.match(/password:\s*(\S+)/)[1];
const textArea = document.createElement('textarea');
textArea.value = new_password;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
alert(_('Username:') + 'admin\n' + _('New Password:') + new_password + '\n\n' + _('New password has been copied to clipboard.'));
} catch (error) {
console.error('Failed to reset password: ', error);
}
},

render: function (data) {
var m, s, o;
var webport = uci.get(data[0], '@alist[0]', 'port') || '5244';
var ssl = uci.get(data[0], '@alist[0]', 'ssl') || '0';
var protocol;
if (ssl === '0') {
protocol = 'http:';
} else if (ssl === '1') {
protocol = 'https:';
}

m = new form.Map('alist', _('Alist'),
_('A file list program that supports multiple storage.') +
'<br><a href="https://alist.nn.ci/zh/guide/drivers/local.html" target="_blank">' +
_('User Manual') +
'</a>');

s = m.section(form.TypedSection);
s.anonymous = true;
s.addremove = false;

s.render = function () {
poll.add(function () {
return L.resolveDefault(getServiceStatus()).then(function (res) {
var view = document.getElementById('service_status');
view.innerHTML = renderStatus(res, protocol, webport);
});
});

return E('div', { class: 'cbi-section', id: 'status_bar' }, [
E('p', { id: 'service_status' }, _('Collecting data...'))
]);
}

s = m.section(form.NamedSection, '@alist[0]', 'alist');

o = s.option(form.Flag, 'enabled', _('Enabled'));
o.default = o.disabled;
o.rmempty = false;

o = s.option(form.Value, 'port', _('Port'));
o.datatype = 'and(port,min(1))';
o.default = '5244';
o.rmempty = false;

o = s.option(form.Flag, 'log', _('Enable Logs'));
o.default = 1;
o.rmempty = false;

o = s.option(form.Flag, 'ssl', _('Enable SSL'));
o.rmempty = false;

o = s.option(form.Value, 'ssl_cert', _('SSL cert'),
_('SSL certificate file path'));
o.rmempty = false;
o.depends('ssl', '1');

o = s.option(form.Value, 'ssl_key', _('SSL key'),
_('SSL key file path'));
o.rmempty = false;
o.depends('ssl', '1');

o = s.option(form.Flag, 'mysql', _('Enable Database'));
o.rmempty = false;

o = s.option(form.ListValue, 'mysql_type', _('Database Type'));
o.default = 'mysql';
o.depends('mysql', '1');
o.value('mysql', _('MySQL'));
o.value('postgres', _('PostgreSQL'));

o = s.option(form.Value, 'mysql_host', _('Database Host'));
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_port', _('Database Port'));
o.datatype = 'port';
o.default = '3306';
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_username', _('Database Username'));
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_password', _('Database Password'));
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_database', _('Database Name'));
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_table_prefix', _('Database Table Prefix'));
o.default = 'x_';
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_ssl_mode', _('Database SSL Mode'));
o.depends('mysql', '1');

o = s.option(form.Value, 'mysql_dsn', _('Database DSN'));
o.depends('mysql', '1');

o = s.option(form.Flag, 'allow_wan', _('Allow Access From Internet'));
o.rmempty = false;

o = s.option(form.Value, 'site_url', _('Site URL'),
_('When the web is reverse proxied to a subdirectory, this option must be filled out to ensure proper functioning of the web. Do not include \'/\' at the end of the URL'));

o = s.option(form.Value, 'max_connections', _('Max Connections'),
_('0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device'));
o.default = '0';
o.datatype = 'uinteger';
o.rmempty = false;

o = s.option(form.Value, 'token_expires_in', _('Login Validity Period (hours)'));
o.datatype = 'uinteger';
o.default = '48';
o.rmempty = false;

o = s.option(form.Value, 'delayed_start', _('Delayed Start (seconds)'));
o.datatype = 'uinteger';
o.default = '0';
o.rmempty = false;

o = s.option(form.Value, 'data_dir', _('Data directory'));
o.default = '/etc/alist';

o = s.option(form.Value, 'temp_dir', _('Cache directory'));
o.default = '/tmp/alist';
o.rmempty = false;

o = s.option(form.Button, '_newpassword', _('Reset Password'),
_('Generate a new random password.'));
o.inputtitle = _('Reset Password');
o.inputstyle = 'apply';
o.onclick = L.bind(this.handleResetPassword, this, data);

return m.render();
}
});
76 changes: 76 additions & 0 deletions luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';
'require dom';
'require fs';
'require poll';
'require view';

function pollLog(e) {
return Promise.all([
fs.read_direct('/var/log/alist.log', 'text').then(function (res) {
return res.trim().split(/\n/).join('\n').replace(/\u001b\[33mWARN\u001b\[0m/g, '').replace(/\u001b\[36mINFO\u001b\[0m/g, '');
}),
]).then(function (data) {
var logTextarea = E('textarea', { 'class': 'cbi-input-textarea', 'wrap': 'off', 'readonly': 'readonly', 'style': 'width: calc(100% - 20px);height: 500px;margin: 10px;overflow-y: scroll;' }, [
data[0] || _('No log data.')
]);

// Store the current scroll position
var storedScrollTop = e.querySelector('textarea') ? e.querySelector('textarea').scrollTop : null;

dom.content(e, logTextarea);

// If the storedScrollTop is not null, it means we have a previous scroll position
if (storedScrollTop !== null) {
logTextarea.scrollTop = storedScrollTop;
}

// Add event listener to save the scroll position when scrolling stops
var timer;
logTextarea.addEventListener('scroll', function () {
clearTimeout(timer);
timer = setTimeout(function () {
storeScrollPosition(logTextarea.scrollTop);
}, 150);
});

function storeScrollPosition(scrollPos) {
localStorage.setItem("scrollPosition", JSON.stringify({ "log": scrollPos }));
}

});
};

return view.extend({
handleCleanLogs: function () {
return fs.write('/var/log/alist.log', '')
.catch(function (e) { ui.addNotification(null, E('p', e.message)) });
},

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));
var clear_logs_button = E('input', { 'class': 'btn cbi-button-action', 'type': 'button', 'style': 'margin-left: 10px; margin-top: 10px;', 'value': _('Clear logs') });
clear_logs_button.addEventListener('click', this.handleCleanLogs.bind(this));
return E([
E('div', { 'class': 'cbi-map' }, [
E('div', { 'class': 'cbi-section' }, [
clear_logs_button,
log_textarea,
E('div', { 'style': 'text-align:right' },
E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval))
)
])])
]);
},

handleSave: null,
handleSaveApply: null,
handleReset: null
});
50 changes: 0 additions & 50 deletions luci-app-alist/luasrc/controller/alist.lua

This file was deleted.

Loading

0 comments on commit 7f3cdca

Please sign in to comment.