From f1d8ebf874c376b53827113f851a2b61ac05fba5 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 14 Aug 2024 08:33:07 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=95=20Sync=202024-08-14=2008:33?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
alist/files/alist.init | 15 +-
luci-app-alist/Makefile | 12 +-
.../luci-static/resources/view/alist/basic.js | 199 ++++++++++++++++++
.../luci-static/resources/view/alist/logs.js | 76 +++++++
luci-app-alist/luasrc/controller/alist.lua | 50 -----
.../luasrc/model/cbi/alist/basic.lua | 113 ----------
luci-app-alist/luasrc/model/cbi/alist/log.lua | 5 -
.../luasrc/view/alist/admin_info.htm | 26 ---
.../luasrc/view/alist/alist_log.htm | 35 ---
.../luasrc/view/alist/alist_status.htm | 36 ----
luci-app-alist/po/zh-cn | 1 +
luci-app-alist/po/zh_Hans | 1 -
luci-app-alist/po/{zh-cn => zh_Hans}/alist.po | 11 +-
.../{50-luci-alist => luci-app-alist} | 0
.../usr/share/luci/menu.d/luci-app-alist.json | 36 ++++
.../usr/share/rpcd/acl.d/luci-app-alist.json | 10 +
.../root/usr/share/serverchan/serverchan | 4 +-
17 files changed, 344 insertions(+), 286 deletions(-)
create mode 100644 luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js
create mode 100644 luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js
delete mode 100644 luci-app-alist/luasrc/controller/alist.lua
delete mode 100644 luci-app-alist/luasrc/model/cbi/alist/basic.lua
delete mode 100644 luci-app-alist/luasrc/model/cbi/alist/log.lua
delete mode 100644 luci-app-alist/luasrc/view/alist/admin_info.htm
delete mode 100644 luci-app-alist/luasrc/view/alist/alist_log.htm
delete mode 100644 luci-app-alist/luasrc/view/alist/alist_status.htm
create mode 120000 luci-app-alist/po/zh-cn
delete mode 120000 luci-app-alist/po/zh_Hans
rename luci-app-alist/po/{zh-cn => zh_Hans}/alist.po (91%)
rename luci-app-alist/root/etc/uci-defaults/{50-luci-alist => luci-app-alist} (100%)
create mode 100644 luci-app-alist/root/usr/share/luci/menu.d/luci-app-alist.json
diff --git a/alist/files/alist.init b/alist/files/alist.init
index 9cde3298..157aa479 100755
--- a/alist/files/alist.init
+++ b/alist/files/alist.init
@@ -5,6 +5,7 @@
START=99
USE_PROCD=1
PROG=/usr/bin/alist
+LOG_FILE=/var/log/alist.log
get_config() {
config_get_bool enabled $1 enabled 1
@@ -84,7 +85,7 @@ start_service() {
[ "$mysql" -eq 1 ] && database=$mysql_type || database=sqlite3
set_firewall
- true > $temp_dir/alist.log
+ true > $LOG_FILE
# init config
json_init
@@ -134,7 +135,7 @@ start_service() {
# log
json_add_object "log"
json_add_boolean "enable" "$log"
- json_add_string "name" "$temp_dir/alist.log"
+ json_add_string "name" "$LOG_FILE"
json_add_int "max_size" "10"
json_add_int "max_backups" "5"
json_add_int "max_age" "28"
@@ -187,7 +188,7 @@ start_service() {
json_dump > $data_dir/config.json
- procd_open_instance
+ procd_open_instance alist
procd_set_param command $PROG
procd_append_param command server --data $data_dir
procd_set_param stdout 0
@@ -195,7 +196,13 @@ start_service() {
procd_set_param respawn
procd_set_param limits core="unlimited"
procd_set_param limits nofile="200000 200000"
- procd_close_instance
+ procd_close_instance alist
+}
+
+reload_service() {
+ stop
+ sleep 3
+ start
}
service_triggers() {
diff --git a/luci-app-alist/Makefile b/luci-app-alist/Makefile
index 9edcd81d..e23ae803 100644
--- a/luci-app-alist/Makefile
+++ b/luci-app-alist/Makefile
@@ -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
diff --git a/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js b/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js
new file mode 100644
index 00000000..3cdebc7f
--- /dev/null
+++ b/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js
@@ -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 = '%s %s';
+ var renderHTML;
+ if (isRunning) {
+ var button = String.format('',
+ _('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.') +
+ '
' +
+ _('User Manual') +
+ '');
+
+ 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.TypedSection);
+
+ 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();
+ }
+});
diff --git a/luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js b/luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js
new file mode 100644
index 00000000..6077c3c3
--- /dev/null
+++ b/luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js
@@ -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
+});
diff --git a/luci-app-alist/luasrc/controller/alist.lua b/luci-app-alist/luasrc/controller/alist.lua
deleted file mode 100644
index d611d5cf..00000000
--- a/luci-app-alist/luasrc/controller/alist.lua
+++ /dev/null
@@ -1,50 +0,0 @@
-module("luci.controller.alist", package.seeall)
-
-function index()
- if not nixio.fs.access("/etc/config/alist") then
- return
- end
-
- local page = entry({"admin", "nas", "alist"}, alias("admin", "nas", "alist", "basic"), _("Alist"), 20)
- page.dependent = true
- page.acl_depends = { "luci-app-alist" }
-
- entry({"admin", "nas"}, firstchild(), "NAS", 44).dependent = false
- entry({"admin", "nas", "alist", "basic"}, cbi("alist/basic"), _("Basic Setting"), 1).leaf = true
- entry({"admin", "nas", "alist", "log"}, cbi("alist/log"), _("Logs"), 2).leaf = true
- entry({"admin", "nas", "alist", "alist_status"}, call("alist_status")).leaf = true
- entry({"admin", "nas", "alist", "get_log"}, call("get_log")).leaf = true
- entry({"admin", "nas", "alist", "clear_log"}, call("clear_log")).leaf = true
- entry({"admin", "nas", "alist", "admin_info"}, call("admin_info")).leaf = true
-end
-
-function alist_status()
- local sys = require "luci.sys"
- local uci = require "luci.model.uci".cursor()
- local port = tonumber(uci:get_first("alist", "alist", "port"))
-
- local status = {
- running = (sys.call("pidof alist >/dev/null") == 0),
- port = (port or 5244)
- }
-
- luci.http.prepare_content("application/json")
- luci.http.write_json(status)
-end
-
-function get_log()
- luci.http.write(luci.sys.exec("cat $(uci -q get alist.@alist[0].temp_dir)/alist.log"))
-end
-
-function clear_log()
- luci.sys.call("cat /dev/null > $(uci -q get alist.@alist[0].temp_dir)/alist.log")
-end
-
-function admin_info()
- local random = luci.sys.exec("/usr/bin/alist --data $(uci -q get alist.@alist[0].data_dir) admin random 2>&1")
- local username = string.match(random, "username: (%S+)")
- local password = string.match(random, "password: (%S+)")
-
- luci.http.prepare_content("application/json")
- luci.http.write_json({username = username, password = password})
-end
diff --git a/luci-app-alist/luasrc/model/cbi/alist/basic.lua b/luci-app-alist/luasrc/model/cbi/alist/basic.lua
deleted file mode 100644
index ec5587a8..00000000
--- a/luci-app-alist/luasrc/model/cbi/alist/basic.lua
+++ /dev/null
@@ -1,113 +0,0 @@
-local m, s
-
-m = Map("alist", translate("Alist"), translate("A file list program that supports multiple storage.") .. "
" .. [[]] .. translate("User Manual") .. [[]])
-
-m:section(SimpleSection).template = "alist/alist_status"
-
-s = m:section(TypedSection, "alist")
-s.addremove = false
-s.anonymous = true
-
-o = s:option(Flag, "enabled", translate("Enabled"))
-o.rmempty = false
-
-o = s:option(Value, "port", translate("Port"))
-o.datatype = "and(port,min(1))"
-o.rmempty = false
-o.default = "5244"
-
-o = s:option(Flag, "log", translate("Enable Logs"))
-o.default = 1
-o.rmempty = false
-
-o = s:option(Flag, "ssl", translate("Enable SSL"))
-o.rmempty=false
-
-o = s:option(Value,"ssl_cert", translate("SSL cert"), translate("SSL certificate file path"))
-o.datatype = "file"
-o:depends("ssl", "1")
-
-o = s:option(Value,"ssl_key", translate("SSL key"), translate("SSL key file path"))
-o.datatype = "file"
-o:depends("ssl", "1")
-
-o = s:option(Flag, "mysql", translate("Enable Database"))
-o.rmempty=false
-
-o = s:option(ListValue, "mysql_type", translate("Database Type"))
-o.datatype = "string"
-o:value("mysql", translate("MySQL"))
-o:value("postgres", translate("PostgreSQL"))
-o.default = "mysql"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_host", translate("Database Host"))
-o.datatype = "string"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_port", translate("Database Port"))
-o.datatype = "and(port,min(1))"
-o.default = "3306"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_username", translate("Database Username"))
-o.datatype = "string"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_password", translate("Database Password"))
-o.datatype = "string"
-o.password = true
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_database", translate("Database Name"))
-o.datatype = "string"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_table_prefix", translate("Database Table Prefix"))
-o.datatype = "string"
-o.default = "x_"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_ssl_mode", translate("Database SSL Mode"))
-o.datatype = "string"
-o:depends("mysql", "1")
-
-o = s:option(Value,"mysql_dsn", translate("Database DSN"))
-o.datatype = "string"
-o:depends("mysql", "1")
-
-o = s:option(Flag, "allow_wan", translate("Allow Access From Internet"))
-o.rmempty = false
-
-o = s:option(Value, "site_url", translate("Site URL"), translate("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.datatype = "string"
-
-o = s:option(Value, "max_connections", translate("Max Connections"), translate("0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device"))
-o.datatype = "and(uinteger,min(0))"
-o.default = "0"
-o.rmempty = false
-
-o = s:option(Value, "token_expires_in", translate("Login Validity Period (hours)"))
-o.datatype = "and(uinteger,min(1))"
-o.default = "48"
-o.rmempty = false
-
-o = s:option(Value, "delayed_start", translate("Delayed Start (seconds)"))
-o.datatype = "and(uinteger,min(0))"
-o.default = "0"
-o.rmempty = false
-
-o = s:option(Value, "data_dir", translate("Data directory"))
-o.datatype = "string"
-o.default = "/etc/alist"
-
-o = s:option(Value, "temp_dir", translate("Cache directory"))
-o.datatype = "string"
-o.default = "/tmp/alist"
-o.rmempty = false
-
-o = s:option(Button, "admin_info", translate("Reset Password"))
-o.rawhtml = true
-o.template = "alist/admin_info"
-
-return m
diff --git a/luci-app-alist/luasrc/model/cbi/alist/log.lua b/luci-app-alist/luasrc/model/cbi/alist/log.lua
deleted file mode 100644
index 4b6c36f8..00000000
--- a/luci-app-alist/luasrc/model/cbi/alist/log.lua
+++ /dev/null
@@ -1,5 +0,0 @@
-m = Map("alist")
-
-m:append(Template("alist/alist_log"))
-
-return m
diff --git a/luci-app-alist/luasrc/view/alist/admin_info.htm b/luci-app-alist/luasrc/view/alist/admin_info.htm
deleted file mode 100644
index ba34e91b..00000000
--- a/luci-app-alist/luasrc/view/alist/admin_info.htm
+++ /dev/null
@@ -1,26 +0,0 @@
-<%+cbi/valueheader%>
-
-
-<%=self.value%>
-<%+cbi/valuefooter%>
\ No newline at end of file
diff --git a/luci-app-alist/luasrc/view/alist/alist_log.htm b/luci-app-alist/luasrc/view/alist/alist_log.htm
deleted file mode 100644
index 5ec4a78b..00000000
--- a/luci-app-alist/luasrc/view/alist/alist_log.htm
+++ /dev/null
@@ -1,35 +0,0 @@
-
-