-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: sbwml <admin@cooluc.com>
- Loading branch information
Showing
14 changed files
with
330 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
76
luci-app-alist/htdocs/luci-static/resources/view/alist/logs.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}); |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.