mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-05 09:54:06 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
Executable
+17
@@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2020-2026 Hyy2001X <https://github.com/Hyy2001X>
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-shutdown
|
||||
PKG_VERSION:=2.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-or-later
|
||||
|
||||
LUCI_TITLE:=LuCI Support for shutdown/reboot
|
||||
LUCI_DEPENDS:=+luci-base
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
## luci-app-shutdown
|
||||
|
||||
一键关闭/重启设备
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
module("luci.controller.shutdown", package.seeall)
|
||||
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local jsonc = require "luci.jsonc"
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local function json_ok(tbl)
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(tbl or { ok = true })
|
||||
end
|
||||
|
||||
local function json_err(msg, code)
|
||||
http.status(code or 500, "Error")
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({ ok = false, error = msg or "unknown error" })
|
||||
end
|
||||
|
||||
local function poweroff_supported()
|
||||
-- OpenWrt 常见:/sbin/poweroff(procd)
|
||||
if fs.access("/sbin/poweroff") then
|
||||
return true, "found /sbin/poweroff"
|
||||
end
|
||||
|
||||
-- BusyBox applet 兜底(有些系统没有独立 /sbin/poweroff)
|
||||
local ret = sys.call("/bin/busybox poweroff -h >/dev/null 2>&1")
|
||||
if ret == 0 then
|
||||
return true, "busybox poweroff applet"
|
||||
end
|
||||
|
||||
return false, "poweroff command not found"
|
||||
end
|
||||
|
||||
local function get_board()
|
||||
local out = sys.exec("ubus call system board 2>/dev/null")
|
||||
local obj = (out and #out > 0) and jsonc.parse(out) or nil
|
||||
return obj or {}
|
||||
end
|
||||
|
||||
function index()
|
||||
local page = entry({"admin", "system", "shutdown"}, cbi("shutdown"), _("Shutdown / Reboot"), 90)
|
||||
page.dependent = true
|
||||
page.acl_depends = { "luci-app-shutdown" }
|
||||
|
||||
-- JSON endpoints
|
||||
entry({"admin", "system", "shutdown", "status"}, call("action_status")).leaf = true
|
||||
entry({"admin", "system", "shutdown", "reboot"}, post("action_reboot")).leaf = true
|
||||
entry({"admin", "system", "shutdown", "poweroff"}, post("action_poweroff")).leaf = true
|
||||
end
|
||||
|
||||
function action_status()
|
||||
local supported, reason = poweroff_supported()
|
||||
local board = get_board()
|
||||
|
||||
json_ok({
|
||||
ok = true,
|
||||
poweroff_supported = supported,
|
||||
poweroff_reason = reason,
|
||||
board = {
|
||||
model = board.model,
|
||||
system = board.system,
|
||||
release = board.release,
|
||||
kernel = board.kernel,
|
||||
hostname = board.hostname
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
function action_reboot()
|
||||
-- 后台执行,先返回 JSON
|
||||
sys.call("(sleep 1; sync; reboot) >/dev/null 2>&1 &")
|
||||
json_ok({ ok = true })
|
||||
end
|
||||
|
||||
function action_poweroff()
|
||||
local supported, reason = poweroff_supported()
|
||||
if not supported then
|
||||
return json_err("Poweroff not supported: " .. (reason or ""), 400)
|
||||
end
|
||||
|
||||
sys.call("(sleep 1; sync; poweroff) >/dev/null 2>&1 &")
|
||||
json_ok({ ok = true })
|
||||
end
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
m = Map("system", translate("Shutdown / Reboot"),
|
||||
translate("Use the buttons below to reboot or shut down the device."))
|
||||
|
||||
s = m:section(SimpleSection)
|
||||
s.template = "shutdown/actions"
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,115 @@
|
||||
<div class="cbi-section">
|
||||
<div class="cbi-section-node">
|
||||
|
||||
<div id="shutdown_info" class="alert-message" style="display:none;"></div>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Device%></label>
|
||||
<div class="cbi-value-field">
|
||||
<strong id="dev_model">-</strong><br />
|
||||
<small id="dev_release">-</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Actions%></label>
|
||||
<div class="cbi-value-field">
|
||||
<button id="btn_reboot" class="cbi-button cbi-button-apply"><%:Reboot%></button>
|
||||
<button id="btn_poweroff" class="cbi-button cbi-button-reset"><%:Shutdown%></button>
|
||||
<span id="poweroff_hint" style="margin-left:8px;"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var statusUrl = '<%=luci.dispatcher.build_url("admin","system","shutdown","status")%>';
|
||||
var rebootUrl = '<%=luci.dispatcher.build_url("admin","system","shutdown","reboot")%>';
|
||||
var poweroffUrl = '<%=luci.dispatcher.build_url("admin","system","shutdown","poweroff")%>';
|
||||
|
||||
var infoBox = document.getElementById('shutdown_info');
|
||||
var btnReboot = document.getElementById('btn_reboot');
|
||||
var btnPoweroff = document.getElementById('btn_poweroff');
|
||||
var hint = document.getElementById('poweroff_hint');
|
||||
|
||||
function showInfo(msg, isErr) {
|
||||
infoBox.style.display = '';
|
||||
infoBox.className = isErr ? 'alert-message error' : 'alert-message success';
|
||||
infoBox.textContent = msg;
|
||||
}
|
||||
|
||||
function setPoweroffAvailable(ok) {
|
||||
if (ok) {
|
||||
btnPoweroff.disabled = false;
|
||||
hint.textContent = '';
|
||||
} else {
|
||||
btnPoweroff.disabled = true;
|
||||
hint.textContent = '(<%:Poweroff is not supported on this device.%>)';
|
||||
}
|
||||
}
|
||||
|
||||
function xhrGet(url, cb) {
|
||||
fetch(url, { method: 'GET', credentials: 'same-origin' })
|
||||
.then(r => r.json()).then(cb)
|
||||
.catch(() => cb(null));
|
||||
}
|
||||
|
||||
function xhrPost(url, cb) {
|
||||
fetch(url, { method: 'POST', credentials: 'same-origin' })
|
||||
.then(r => r.json()).then(cb)
|
||||
.catch(() => cb(null));
|
||||
}
|
||||
|
||||
function loadStatus() {
|
||||
xhrGet(statusUrl, function(data) {
|
||||
if (!data || !data.ok) {
|
||||
showInfo('<%:Failed to load status.%>', true);
|
||||
setPoweroffAvailable(false, 'status unavailable');
|
||||
return;
|
||||
}
|
||||
|
||||
var board = data.board || {};
|
||||
document.getElementById('dev_model').textContent =
|
||||
board.model || board.system || '-';
|
||||
|
||||
var rel = board.release || {};
|
||||
var relTxt = [];
|
||||
if (rel.distribution) relTxt.push(rel.distribution);
|
||||
if (rel.version) relTxt.push(rel.version);
|
||||
if (rel.revision) relTxt.push(rel.revision);
|
||||
document.getElementById('dev_release').textContent = relTxt.join(' ') || '-';
|
||||
|
||||
setPoweroffAvailable(!!data.poweroff_supported);
|
||||
});
|
||||
}
|
||||
|
||||
btnReboot.addEventListener('click', function() {
|
||||
if (!confirm('<%:Are you sure you want to reboot the system?%>'))
|
||||
return;
|
||||
|
||||
btnReboot.disabled = true;
|
||||
|
||||
xhrPost(rebootUrl, function() {
|
||||
/* no ui feedback, system will reboot */
|
||||
});
|
||||
});
|
||||
|
||||
btnPoweroff.addEventListener('click', function() {
|
||||
if (btnPoweroff.disabled)
|
||||
return;
|
||||
|
||||
if (!confirm('<%:Are you sure you want to shut down the system?%>'))
|
||||
return;
|
||||
|
||||
btnPoweroff.disabled = true;
|
||||
|
||||
xhrPost(poweroffUrl, function() {
|
||||
/* no ui feedback, system will power off */
|
||||
});
|
||||
});
|
||||
|
||||
loadStatus();
|
||||
})();
|
||||
</script>
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Language: zh-cn\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Shutdown / Reboot"
|
||||
msgstr "关机 / 重启"
|
||||
|
||||
msgid "Use the buttons below to reboot or shut down the device."
|
||||
msgstr "使用下方按钮执行重启或关机。"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "设备"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr "操作"
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr "重启"
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr "关机"
|
||||
|
||||
msgid "Not supported"
|
||||
msgstr "不支持"
|
||||
|
||||
msgid "Failed to load status."
|
||||
msgstr "加载状态失败。"
|
||||
|
||||
msgid "Are you sure you want to reboot the system?"
|
||||
msgstr "确认要重启系统吗?"
|
||||
|
||||
msgid "Are you sure you want to shut down the system?"
|
||||
msgstr "确认要关闭系统吗?"
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Language: zh_Hans\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Shutdown / Reboot"
|
||||
msgstr "关机 / 重启"
|
||||
|
||||
msgid "Use the buttons below to reboot or shut down the device."
|
||||
msgstr "使用下方按钮执行重启或关机。"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "设备"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr "操作"
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr "重启"
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr "关机"
|
||||
|
||||
msgid "Not supported"
|
||||
msgstr "不支持"
|
||||
|
||||
msgid "Failed to load status."
|
||||
msgstr "加载状态失败。"
|
||||
|
||||
msgid "Are you sure you want to reboot the system?"
|
||||
msgstr "确认要重启系统吗?"
|
||||
|
||||
msgid "Are you sure you want to shut down the system?"
|
||||
msgstr "确认要关闭系统吗?"
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"luci-app-shutdown": {
|
||||
"description": "Grant access to LuCI shutdown/reboot app",
|
||||
"read": {
|
||||
"luci": [ "shutdown" ],
|
||||
"uci": [ "system" ]
|
||||
},
|
||||
"write": {
|
||||
"luci": [ "shutdown" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user