mirror of https://github.com/OpenIPC/composer.git
Add hi3516ev300 meldana project
parent
37d8cb2e69
commit
680429f5f2
|
@ -0,0 +1 @@
|
||||||
|
hi3516ev300_lite_defconfig
|
|
@ -0,0 +1,2 @@
|
||||||
|
#
|
||||||
|
composer_message="This firmware was created with the Composer project."
|
|
@ -0,0 +1 @@
|
||||||
|
meldana
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="width=device-width,initial-scale=1" name="viewport">
|
||||||
|
<title>Необходима аутентификация</title>
|
||||||
|
<link href="/a/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="/a/bootstrap.override.css" rel="stylesheet">
|
||||||
|
<script src="/a/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="/a/main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body id="top">
|
||||||
|
<nav class="navbar navbar-expand-lg sticky-top">
|
||||||
|
<div class="container"><a class="navbar-brand" href="/cgi-bin/status.cgi"><img alt="" height="32" src="/a/logo.svg" width="116"></a></div>
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<div class="container p-3"><h2>Необходима аутентификация</h2>
|
||||||
|
<div class="alert alert-info"><h3>Утомительно, да?</h3>
|
||||||
|
<p>Вы пытались использовать имя пользователя «root» и пароль «12345»?</p>
|
||||||
|
<p>Вы можете найти больше полезной информации в <a href="https://openipc.org/wiki/">нашем Вики</a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer class="p-3">
|
||||||
|
<div class="container">
|
||||||
|
<p class="text-end">Работает на <a href="https://github.com/OpenIPC/microbe-web">Microbe Web UI</a>,
|
||||||
|
части <a href="https://openipc.org/">OpenIPC </a>, доработано
|
||||||
|
<a href="https://meldana.com/services/remont-i-razrabotka/razrabotka-elektroniki/">Meldana RND</a>.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,280 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans:wght@400;700&display=swap');
|
||||||
|
|
||||||
|
/* debugging start */
|
||||||
|
@media (max-width: 575.98px) {body.debug:before{content:"xs"}}
|
||||||
|
@media (min-width: 576px) and (max-width: 767.98px) {body.debug:before{content:"sm"}}
|
||||||
|
@media (min-width: 768px) and (max-width: 991.98px) {body.debug:before{content:"md"}}
|
||||||
|
@media (min-width: 992px) and (max-width: 1199.98px) {body.debug:before{content:"lg"}}
|
||||||
|
@media (min-width: 1200px) and (max-width: 1399.98px) {body.debug:before{content:"xl"}}
|
||||||
|
@media (min-width: 1400px) {body.debug:before{content:"xxl"}}
|
||||||
|
|
||||||
|
body.debug:before {
|
||||||
|
color:#4c60d811;
|
||||||
|
display:block;
|
||||||
|
font-size:10rem;
|
||||||
|
font-variant:all-small-caps;
|
||||||
|
font-weight:700;
|
||||||
|
line-height:1;
|
||||||
|
position:fixed;
|
||||||
|
right:3rem;
|
||||||
|
top:3rem;
|
||||||
|
z-index:-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offcanvas {
|
||||||
|
--bs-offcanvas-width: 30vw;
|
||||||
|
min-width: 25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#debug-button {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1rem;
|
||||||
|
left: 1rem;
|
||||||
|
}
|
||||||
|
/* debugging end */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bs-body-font-family: "IBM Plex Sans", sans-serif;
|
||||||
|
--bs-font-monospace: "IBM Plex Mono", monospace;
|
||||||
|
--bs-blue: rgb(76, 96, 216);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme=light] {
|
||||||
|
--bs-primary: rgb(76, 96, 216);
|
||||||
|
--bs-secondary: rgb(76, 96, 216);
|
||||||
|
--bs-tertiary-bg-rgb: 76, 96, 216;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav,
|
||||||
|
[data-bs-theme=light] .navbar-nav {
|
||||||
|
--bs-nav-link-color: white;
|
||||||
|
}
|
||||||
|
[data-bs-theme=light] .nav-link {
|
||||||
|
color: var(--bs-nav-link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme=dark] {
|
||||||
|
--bs-primary: rgb(76, 96, 216);
|
||||||
|
--bs-secondary: rgb(138, 159, 208);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme=dark] .btn-primary {
|
||||||
|
--bs-btn-color: #fff;
|
||||||
|
--bs-btn-bg: rgba(13, 110, 253, 0.5);
|
||||||
|
--bs-btn-border-color: rgba(13, 110, 253, 0.5);
|
||||||
|
--bs-btn-hover-color: #fff;
|
||||||
|
--bs-btn-hover-bg: rgba(11, 94, 215, 0.5);
|
||||||
|
--bs-btn-hover-border-color: rgba(10, 88, 202, 0.5);
|
||||||
|
--bs-btn-focus-shadow-rgb: 49,132,253;
|
||||||
|
--bs-btn-active-color: rgba(255, 255, 255, 0.5);
|
||||||
|
--bs-btn-active-bg: rgba(10, 88, 202, 0.5);
|
||||||
|
--bs-btn-active-border-color: rgba(10, 83, 190, 0.5);
|
||||||
|
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||||
|
--bs-btn-disabled-color: rgba(255, 255, 255, 0.5);
|
||||||
|
--bs-btn-disabled-bg: rgba(13, 110, 253, 0.5);
|
||||||
|
--bs-btn-disabled-border-color: rgba(13, 110, 253, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
body > main > .container > h2 {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--bs-primary);
|
||||||
|
margin: 1rem 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: #4c60d812;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.list b {
|
||||||
|
display: inline-block;
|
||||||
|
width: 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
font-family: var(--bs-font-monospace);
|
||||||
|
height: 50vh;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.list {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.list dt {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.list dd {
|
||||||
|
flex-grow: 2;
|
||||||
|
width: 66%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col > h3 {
|
||||||
|
color: var(--bs-secondary);
|
||||||
|
font-size: 1.3rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp2cb {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control.font-monospace {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control::placeholder {
|
||||||
|
color: #c2c2d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
margin-bottom: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-range {
|
||||||
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-range::-moz-range-track {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.range span.show-value {
|
||||||
|
display: block;
|
||||||
|
min-width: 3.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link.active {
|
||||||
|
background: var(--bs-primary);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-pane {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-texteditor .tab-pane {
|
||||||
|
min-height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range-value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.25rem;
|
||||||
|
top: -0.75rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social a {
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social a img {
|
||||||
|
height: 1.25rem;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x-small {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mj-tabs .list-group-item {
|
||||||
|
padding: 0.25rem 1.0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#soc-temp {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
/*border-radius: 5px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
pre#output[data-cmd] { background-color: rgb(0, 0, 0); color: rgba(170, 170, 170, 0.8); }
|
||||||
|
.ansi-30 { color: rgba(0, 0, 0, 0.8); }
|
||||||
|
.ansi-31 { color: rgba(170, 0, 0, 0.8); }
|
||||||
|
.ansi-32 { color: rgba(0, 170, 0, 0.8); }
|
||||||
|
.ansi-33 { color: rgba(170, 85, 0, 0.8); }
|
||||||
|
.ansi-34 { color: rgba(0, 0, 170, 0.8); }
|
||||||
|
.ansi-35 { color: rgba(170, 0, 170, 0.8); }
|
||||||
|
.ansi-36 { color: rgba(0, 170, 170, 0.8); }
|
||||||
|
.ansi-37 { color: rgba(170, 170, 170, 0.8); }
|
||||||
|
|
||||||
|
.ansi-40 { background-color: rgba(0, 0, 0, 0.8); }
|
||||||
|
.ansi-41 { background-color: rgba(255, 0, 0, 0.8); }
|
||||||
|
.ansi-42 { background-color: rgba(0, 128, 0, 0.8); }
|
||||||
|
.ansi-43 { background-color: rgba(255, 255, 0, 0.8); }
|
||||||
|
.ansi-44 { background-color: rgba(0, 0, 255, 0.8); }
|
||||||
|
.ansi-45 { background-color: rgba(255, 0, 255, 0.8); }
|
||||||
|
.ansi-46 { background-color: rgba(0, 255, 255, 0.8); }
|
||||||
|
.ansi-47 { background-color: rgba(255, 255, 255, 0.8); }
|
||||||
|
|
||||||
|
.ansi-90 { color: rgb(0, 0, 0); font-weight: 700; }
|
||||||
|
.ansi-91 { color: rgb(255, 0, 0); font-weight: 700; }
|
||||||
|
.ansi-92 { color: rgb(0, 128, 0); font-weight: 700; }
|
||||||
|
.ansi-93 { color: rgb(255, 255, 0); font-weight: 700; }
|
||||||
|
.ansi-94 { color: rgb(0, 0, 255); font-weight: 700; }
|
||||||
|
.ansi-95 { color: rgb(255, 0, 255); font-weight: 700; }
|
||||||
|
.ansi-96 { color: rgb(0, 255, 255); font-weight: 700; }
|
||||||
|
.ansi-97 { color: rgb(255, 255, 255); font-weight: 700; }
|
||||||
|
|
||||||
|
.ansi-100 { background-color: rgb(0, 0, 0); }
|
||||||
|
.ansi-101 { background-color: rgb(255, 0, 0); }
|
||||||
|
.ansi-102 { background-color: rgb(0, 128, 0); }
|
||||||
|
.ansi-103 { background-color: rgb(255, 255, 0); }
|
||||||
|
.ansi-104 { background-color: rgb(0, 0, 255); }
|
||||||
|
.ansi-105 { background-color: rgb(255, 0, 255); }
|
||||||
|
.ansi-106 { background-color: rgb(0, 255, 255); }
|
||||||
|
.ansi-107 { background-color: rgb(255, 255, 255); }
|
||||||
|
|
||||||
|
body.lite .ult { display: none; }
|
||||||
|
|
||||||
|
body.user .ui-expert { display: none; }
|
||||||
|
body.expert .ui-expert { display: initial; }
|
||||||
|
|
||||||
|
.plugin-enabled {
|
||||||
|
border-left: 5px solid green;
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pb-memory, #pb-overlay { height: 4px; cursor: pointer; }
|
Binary file not shown.
After Width: | Height: | Size: 934 B |
Binary file not shown.
|
@ -0,0 +1,180 @@
|
||||||
|
let max = 0;
|
||||||
|
|
||||||
|
function $(n) {
|
||||||
|
return document.querySelector(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
function $$(n) {
|
||||||
|
return document.querySelectorAll(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
function setProgressBar(id, value, name) {
|
||||||
|
$(id).setAttribute('aria-valuenow', value);
|
||||||
|
$(id).title = name + ': ' + value + '%'
|
||||||
|
const pb = $(id + ' .progress-bar');
|
||||||
|
pb.style.width = value + '%';
|
||||||
|
pb.classList = 'progress-bar';
|
||||||
|
if (value > 95) {
|
||||||
|
pb.classList.add('bg-danger');
|
||||||
|
} else if (value > 90) {
|
||||||
|
pb.classList.add('bg-warning');
|
||||||
|
} else {
|
||||||
|
pb.classList.add('bg-success');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function heartbeat() {
|
||||||
|
fetch('/cgi-bin/j/heartbeat.cgi')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
if (json.soc_temp !== '') {
|
||||||
|
const st = $('#soc-temp')
|
||||||
|
st.textContent = json.soc_temp;
|
||||||
|
st.classList.add(['text-primary','bg-white','rounded','small']);
|
||||||
|
st.title = 'SoC temperature ' + json.soc_temp;
|
||||||
|
}
|
||||||
|
if (json.time_now !== '') {
|
||||||
|
const d = new Date(json.time_now * 1000);
|
||||||
|
$('#time-now').textContent = d.toLocaleString() + ' ' + json.timezone;
|
||||||
|
}
|
||||||
|
if (json.mem_used !== '') {
|
||||||
|
setProgressBar('#pb-memory', json.mem_used, 'Memory Usage');
|
||||||
|
}
|
||||||
|
if (json.overlay_used !== '') {
|
||||||
|
setProgressBar('#pb-overlay', json.overlay_used, 'Overlay Usage');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(setTimeout(heartbeat, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
function initAll() {
|
||||||
|
// serve auto value on range form fields
|
||||||
|
function toggleAuto(el) {
|
||||||
|
const id = el.dataset.for;
|
||||||
|
const p = $('#' + id);
|
||||||
|
const r = $('#' + id + '-range');
|
||||||
|
const s = $('#' + id + '-show');
|
||||||
|
if (el.checked) {
|
||||||
|
el.dataset.value = r.value;
|
||||||
|
p.value = 'auto';
|
||||||
|
r.disabled = true;
|
||||||
|
s.textContent = '--';
|
||||||
|
} else {
|
||||||
|
p.value = el.dataset.value;
|
||||||
|
r.value = p.value;
|
||||||
|
r.disabled = false;
|
||||||
|
s.textContent = p.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$$('form').forEach(el => el.autocomplete = 'off');
|
||||||
|
|
||||||
|
// For .warning and .danger buttons, ask confirmation on action.
|
||||||
|
$$('.btn-danger, .btn-warning, .confirm').forEach(el => {
|
||||||
|
// for input, find its parent form and attach listener to it submit event
|
||||||
|
if (el.nodeName === "INPUT") {
|
||||||
|
while (el.nodeName !== "FORM") el = el.parentNode
|
||||||
|
el.addEventListener('submit', ev => (!confirm("Вы уверены?")) ? ev.preventDefault() : null)
|
||||||
|
} else {
|
||||||
|
el.addEventListener('click', ev => (!confirm("Вы уверены?")) ? ev.preventDefault() : null)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$$('.refresh').forEach(el => el.addEventListener('click', refresh));
|
||||||
|
|
||||||
|
// open links to external resources in a new window.
|
||||||
|
$$('a[href^=http]').forEach(el => el.target = '_blank');
|
||||||
|
|
||||||
|
// add auto toggle button and value display for range elements.
|
||||||
|
$$('input[type=range]').forEach(el => {
|
||||||
|
el.addEventListener('input', ev => {
|
||||||
|
const id = ev.target.id.replace(/-range/, '');`1`
|
||||||
|
$('#' + id + '-show').textContent = ev.target.value;
|
||||||
|
$('#' + id).value = ev.target.value;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$$('input.auto-value').forEach(el => {
|
||||||
|
el.addEventListener('click', ev => toggleAuto(ev.target));
|
||||||
|
toggleAuto(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
// const resizeObserver = new ResizeObserver(entries => {
|
||||||
|
// entries.forEach(entry => {
|
||||||
|
// if (entry.target.clientHeight > document.documentElement.clientHeight / 2) {
|
||||||
|
// entry.target.classList.add("log-scroll");
|
||||||
|
// entry.target.scrollTo(0, entry.target.scrollHeight);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// $$('pre').forEach(el => resizeObserver.observe(el));
|
||||||
|
|
||||||
|
// show password when "show" checkbox is checked
|
||||||
|
$$(".password input[type=checkbox]").forEach(el => {
|
||||||
|
el.addEventListener('change', ev => {
|
||||||
|
const pw = $('#' + ev.target.dataset['for']);
|
||||||
|
pw.type = (el.checked) ? 'text' : 'password';
|
||||||
|
pw.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// async output of a command running on camera
|
||||||
|
if ($('pre#output[data-cmd]')) {
|
||||||
|
const el = $('pre#output[data-cmd]');
|
||||||
|
async function* makeTextFileLineIterator(url) {
|
||||||
|
const td = new TextDecoder('utf-8');
|
||||||
|
const response = await fetch(url);
|
||||||
|
const rd = response.body.getReader();
|
||||||
|
let { value: chunk, done: readerDone } = await rd.read();
|
||||||
|
chunk = chunk ? td.decode(chunk) : '';
|
||||||
|
const re = /\n|\r|\r\n/gm;
|
||||||
|
let startIndex = 0;
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
for (;;) {
|
||||||
|
result = re.exec(chunk);
|
||||||
|
if (!result) {
|
||||||
|
if (readerDone) break;
|
||||||
|
let remainder = chunk.substr(startIndex);
|
||||||
|
({value: chunk, done: readerDone} = await rd.read());
|
||||||
|
chunk = remainder + (chunk ? td.decode(chunk) : '');
|
||||||
|
startIndex = re.lastIndex = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
yield chunk.substring(startIndex, result.index);
|
||||||
|
startIndex = re.lastIndex;
|
||||||
|
}
|
||||||
|
if (startIndex < chunk.length) yield chunk.substr(startIndex);
|
||||||
|
} finally {
|
||||||
|
if ("true" === el.dataset["reboot"]) {
|
||||||
|
window.location.href = '/cgi-bin/reboot.cgi'
|
||||||
|
} else {
|
||||||
|
el.innerHTML += '\n--- finished ---\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function run() {
|
||||||
|
for await (let line of makeTextFileLineIterator('/cgi-bin/j/run.cgi?cmd=' + btoa(el.dataset["cmd"]))) {
|
||||||
|
const re1 = /\[1;(\d+)m/;
|
||||||
|
const re2 = /\[0m/;
|
||||||
|
line = line.replace(re1, '<span class="ansi-$1">').replace(re2, '</span>')
|
||||||
|
el.innerHTML += line + '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
heartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', initAll);
|
||||||
|
})();
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
Date: <%= $(TZ=GMT0 date +"%a, %d %b %Y %T %Z" --date @$(( $(TZ=GMT0 date +%s) + 1000 ))) %>
|
||||||
|
Server: <%= $SERVER_SOFTWARE %>
|
||||||
|
Content-type: application/javascript; charset=UTF-8
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
<%
|
||||||
|
o=""
|
||||||
|
echo -n "readConfigYaml({"
|
||||||
|
for l in $(sed -n "/^\../p" p/mj.cgi|cut -d\| -f1); do
|
||||||
|
d=${l%.*}; d=${d/./}; name=${l##*.}
|
||||||
|
value=$(yaml-cli -g "$l")
|
||||||
|
if [ "$o" != "$d" ]; then
|
||||||
|
[ -n "$o" ] && echo -n "},"
|
||||||
|
o="$d"
|
||||||
|
echo -n "\"${d}\":{"
|
||||||
|
else
|
||||||
|
echo -n ","
|
||||||
|
fi
|
||||||
|
echo -n "\"${name}\":\"${value}\""
|
||||||
|
done
|
||||||
|
echo -n "}});"
|
||||||
|
%>
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
file=$GET_file
|
||||||
|
if [ "/tmp/webui.log" = "$file" ]; then
|
||||||
|
fname="webui-$(date +%s).log"
|
||||||
|
mime="text/plain"
|
||||||
|
else
|
||||||
|
fname=$(basename $file)
|
||||||
|
mime="application/octet-stream"
|
||||||
|
fi
|
||||||
|
check_file_exist $file
|
||||||
|
echo "HTTP/1.0 200 OK
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Content-type: ${mime}
|
||||||
|
Content-Disposition: attachment; filename=${fname}
|
||||||
|
Content-Length: $(stat -c%s $file)
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
"
|
||||||
|
cat $file
|
||||||
|
%>
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
file=$(mktemp)
|
||||||
|
log="$GET_log"
|
||||||
|
case "$log" in
|
||||||
|
dmesg) dmesg >$file ;;
|
||||||
|
logread) logread >$file ;;
|
||||||
|
netstat) netstat -a >$file ;;
|
||||||
|
*) echo "Unknown file." && exit 1 ;;
|
||||||
|
esac
|
||||||
|
check_file_exist $file
|
||||||
|
echo "HTTP/1.0 200 OK
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Content-type: text/plain
|
||||||
|
Content-Disposition: attachment; filename=${log}-$(date +%s).txt
|
||||||
|
Content-Length: $(stat -c%s $file)
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
"
|
||||||
|
cat $file
|
||||||
|
rm $file
|
||||||
|
%>
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Удаление оверлея" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<pre class="bg-light p-4 log-scroll">
|
||||||
|
<% sysupgrade -n %>
|
||||||
|
</pre>
|
||||||
|
<a class="btn btn-primary" href="/">Вернуться на главную</a>
|
||||||
|
<a class="btn btn-danger" href="reboot.cgi">Перезагрузить камеру</a>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Обновление прошивки"
|
||||||
|
c="/usr/sbin/sysupgrade"
|
||||||
|
reboot="true"
|
||||||
|
[ "true" = "$POST_fw_kernel" ] && c="${c} -k"
|
||||||
|
[ "true" = "$POST_fw_rootfs" ] && c="${c} -r"
|
||||||
|
[ "true" = "$POST_fw_reset" ] && c="${c} -n"
|
||||||
|
[ "true" = "$POST_fw_noreboot" ] && c="${c} -x" && reboot="false"
|
||||||
|
[ "true" = "$POST_fw_enforce" ] && c="${c} --force_ver"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<h3 class="alert alert-warning">НЕ ЗАКРЫВАЙТЕ, НЕ ОБНОВЛЯЙТЕ ИЛИ НЕ УХОДИТЕ С ЭТОЙ СТРАНИЦЫ, ПОКА ПРОЦЕСС НЕ ЗАВЕРШЕН!</h3>
|
||||||
|
<h5># <%= $c %></h5>
|
||||||
|
<pre id="output" data-cmd="<%= $c %>" data-reboot="<%= $reboot %>"></pre>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/haserl --upload-limit=5120 --upload-dir=/tmp
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
sysupgrade_date=$(ls -lc --full-time /usr/sbin/sysupgrade | xargs | cut -d' ' -f6)
|
||||||
|
sysupgrade_date=$(time_epoch "$sysupgrade_date")
|
||||||
|
|
||||||
|
file="$POST_parts_file"
|
||||||
|
file_name="$POST_parts_file_name"
|
||||||
|
error=""
|
||||||
|
|
||||||
|
case "$POST_parts_type" in
|
||||||
|
kernel)
|
||||||
|
maxsize=2097152
|
||||||
|
magicnum="27051956"
|
||||||
|
new_sysupgrade_date=$(time_epoch "2021-12-07")
|
||||||
|
cmd="sysupgrade --kernel=/tmp/${file_name} --force_ver"
|
||||||
|
;;
|
||||||
|
rootfs)
|
||||||
|
maxsize=5242880
|
||||||
|
magicnum="68737173"
|
||||||
|
new_sysupgrade_date=$(time_epoch "2022-02-22")
|
||||||
|
cmd="sysupgrade --rootfs=/tmp/${file_name} --force_ver --force_all"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error="Пожалуйста, выберите тип файла и загрузите его снова!"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ -z "$file_name" ] && error="Файл не найден! Вы не забыли загрузить?"
|
||||||
|
[ ! -r "$file" ] && error="Невозможно прочитать загруженный файл!"
|
||||||
|
[ "$(stat -c%s $file)" -gt "$maxsize" ] && error="Загруженный файл слишком большой! $(stat -c%s $file) > ${maxsize}."
|
||||||
|
[ "$magicnum" -ne "$(xxd -p -l 4 $file)" ] && error="Магический номер файла не совпадает. Вы загрузили неправильный файл? $(xxd -p -l 4 $file) != $magicnum"
|
||||||
|
[ "$sysupgrade_date" -lt "$new_sysupgrade_date" ] && error="Для этой функции требуется последняя версия инструмента sysupgrade. Сначала обновите прошивку."
|
||||||
|
|
||||||
|
if [ -n "$error" ]; then
|
||||||
|
redirect_back "danger" "$error"
|
||||||
|
else %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<pre class="bg-light p-4 log-scroll">
|
||||||
|
<%
|
||||||
|
xl "mv $file /tmp/${file_name}"
|
||||||
|
$cmd
|
||||||
|
%>
|
||||||
|
</pre>
|
||||||
|
<a class="btn btn-primary" href="/">Вернуться на главную</a>
|
||||||
|
<% fi %>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Обновление прошивки"
|
||||||
|
if [ -n "$network_gateway" ]; then
|
||||||
|
case "$soc" in
|
||||||
|
# Ingenic firmware does not correspond to SoC model
|
||||||
|
t10*) url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t10-lite-nor.tgz" ;;
|
||||||
|
t20*) url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t20-lite-nor.tgz" ;;
|
||||||
|
t21*) url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t21-lite-nor.tgz" ;;
|
||||||
|
t31*) url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t31-line-nor.tgz" ;;
|
||||||
|
*) url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.${soc}-${flash_type}-${fw_variant}.tgz" ;;
|
||||||
|
esac
|
||||||
|
fw_date=$(date -D "%a, %d %b %Y %T GMT" +"2.3.%m.%d" --date "$(curl -ILs "$url" | grep Last-Modified | cut -d' ' -f2-)")
|
||||||
|
else
|
||||||
|
fw_date="<span class=\"text-danger\">- Нет доступа к GitHub -</span>"
|
||||||
|
fi
|
||||||
|
fw_kernel="true"
|
||||||
|
fw_rootfs="true"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Версия</h3>
|
||||||
|
<dl class="list small">
|
||||||
|
<dt>Установленная</dt>
|
||||||
|
<dd><%= $fw_version %></dd>
|
||||||
|
<dt>На GitHub</dt>
|
||||||
|
<dd id="firmware-master-ver"><%= $fw_date %></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Обновление</h3>
|
||||||
|
<% if [ -n "$network_gateway" ]; then %>
|
||||||
|
<form action="firmware-update.cgi" method="post">
|
||||||
|
<% field_checkbox "fw_kernel" "Обновить ядро." %>
|
||||||
|
<% field_checkbox "fw_rootfs" "Обновить корневую файловую систему." %>
|
||||||
|
<% field_checkbox "fw_reset" "Сбросить прошивку." %>
|
||||||
|
<% field_checkbox "fw_noreboot" "Не перезагружать после обновления." %>
|
||||||
|
<% field_checkbox "fw_enforce" "Установить, даже если соответствует существующей версии." %>
|
||||||
|
<% button_submit "Установить обновление с GitHub" "warning" %>
|
||||||
|
</form>
|
||||||
|
<% else %>
|
||||||
|
<p class="alert alert-danger">Для обновления требуется доступ к GitHub.</p>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Обновить ядро корневую файловую систему</h3>
|
||||||
|
<form action="firmware-upload-parts.cgi" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_file "parts_file" "Бинарный файл" %>
|
||||||
|
<% field_select "parts_type" "Тип бинарного файла" "kernel, rootfs" %>
|
||||||
|
<p class="text-danger small">Опасно! Убедитесь, что вы знаете, что делаете.</p>
|
||||||
|
<% button_submit "Загрузить файл" "danger" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
preview=/tmp/preview.jpg
|
||||||
|
wget -q -O $preview http://127.0.0.1/image.jpg
|
||||||
|
if [ ! -f "$preview" ]; then
|
||||||
|
echo "HTTP/1.0 404"
|
||||||
|
else
|
||||||
|
echo "HTTP/1.1 200 OK
|
||||||
|
Content-type: image/jpeg
|
||||||
|
Content-Length: $(stat -c%s $preview)
|
||||||
|
Pragma: no-cache
|
||||||
|
Date: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
|
||||||
|
Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
|
||||||
|
Etag: \"$(cat /proc/sys/kernel/random/uuid)\"
|
||||||
|
Connecton: close
|
||||||
|
"
|
||||||
|
cat $preview
|
||||||
|
rm $preview
|
||||||
|
fi
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
actions="info i2cdetect reginfo"
|
||||||
|
action=$GET_action
|
||||||
|
if [ -z "$action" ]; then
|
||||||
|
action=$(echo $actions | awk '{print $1}')
|
||||||
|
redirect_to "${SCRIPT_NAME}?action=${action}"
|
||||||
|
fi
|
||||||
|
command="ipctool"
|
||||||
|
page_title="IPC Tool"
|
||||||
|
if [ "$action" = "info" ]; then
|
||||||
|
command="${command}"
|
||||||
|
page_title="${page_title}: Camera Information"
|
||||||
|
else
|
||||||
|
command="${command} ${action}"
|
||||||
|
page_title="${page_title}: ${action}"
|
||||||
|
fi
|
||||||
|
# ipctool i2cdump 0x78 0x0 0x3ff
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<p><%
|
||||||
|
for c in $actions; do
|
||||||
|
css="btn btn-sm btn-primary"
|
||||||
|
[ "$c" = "$action" ] && css="${css} active"
|
||||||
|
echo "<a class=\"${css}\" href=\"${SCRIPT_NAME}?action=${c}\">${c}</a>"
|
||||||
|
done
|
||||||
|
%>
|
||||||
|
</p>
|
||||||
|
<% ex "${command}" %>
|
||||||
|
<% button_refresh %>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Majestic config" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<% ex "cat /etc/majestic.yaml" %>
|
||||||
|
<p><a class="btn btn-warning" href="texteditor.cgi?f=/etc/majestic.yaml">Edit file</a></p>
|
||||||
|
<% button_restore_from_rom "/etc/majestic.yaml" %>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Топ процессов" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<% ex "top -n 1 -b" %>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
cp /rom/etc/ntp.conf /etc/ntp.conf
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
payload='{"result":"success","message":"Конфигурация сброшена на настройки прошивки по умолчанию."}'
|
||||||
|
else
|
||||||
|
payload='{"result":"danger","message":"Сброс настроек прошивки по умолчанию не удался!"}'
|
||||||
|
fi
|
||||||
|
echo "HTTP/1.1 200 OK
|
||||||
|
Content-type: application/json
|
||||||
|
Pragma: no-cache
|
||||||
|
Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
|
||||||
|
Etag: \"$(cat /proc/sys/kernel/random/uuid)\"
|
||||||
|
|
||||||
|
${payload}
|
||||||
|
"
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
/usr/sbin/ntpd -n -q -N
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
payload='{"result":"success","message":"Время камеры синхронизировано с сервером NTP."}'
|
||||||
|
else
|
||||||
|
payload='{"result":"danger","message":"Синхронизация не удалась!"}'
|
||||||
|
fi
|
||||||
|
echo "HTTP/1.1 200 OK
|
||||||
|
Content-type: application/json
|
||||||
|
Pragma: no-cache
|
||||||
|
Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
|
||||||
|
Etag: \"$(cat /proc/sys/kernel/random/uuid)\"
|
||||||
|
|
||||||
|
${payload}
|
||||||
|
"
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/usr/bin/haserl --upload-limit=20 --upload-dir=/tmp
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
config_file=/etc/majestic.yaml
|
||||||
|
config_file_fw=/rom/etc/majestic.yaml
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
backup)
|
||||||
|
echo "HTTP/1.0 200 OK
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Content-type: text/plain
|
||||||
|
Content-Disposition: attachment; filename=majestic.yaml
|
||||||
|
Content-Length: $(stat -c%s $config_file)
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
"
|
||||||
|
cat $config_file
|
||||||
|
;;
|
||||||
|
patch)
|
||||||
|
patch_file=/tmp/majestic.patch
|
||||||
|
diff $config_file_fw $config_file >$patch_file
|
||||||
|
echo "HTTP/1.0 200 OK
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Content-type: text/plain
|
||||||
|
Content-Disposition: attachment; filename=majestic.$(time_epoch).patch
|
||||||
|
Content-Length: $(stat -c%s $patch_file)
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
"
|
||||||
|
cat $patch_file
|
||||||
|
rm $patch_file
|
||||||
|
;;
|
||||||
|
reset)
|
||||||
|
/usr/sbin/sysreset.sh -m
|
||||||
|
redirect_back
|
||||||
|
;;
|
||||||
|
restore)
|
||||||
|
magicnum="23206d616a6573746963"
|
||||||
|
file="$POST_mj_restore_file"
|
||||||
|
file_name="$POST_mj_restore_file_name"
|
||||||
|
file_path="$POST_mj_restore_file_path"
|
||||||
|
error=""
|
||||||
|
[ -z "$file_name" ] && error="Файл не найден! Вы не забыли загрузить?"
|
||||||
|
[ ! -r "$file" ] && error="Невозможно прочитать загруженный файл!"
|
||||||
|
[ "$(stat -c%s $file)" -gt "$maxsize" ] && error="Загруженный файл слишком большой! $(stat -c%s $file) > ${maxsize}."
|
||||||
|
#[ "$magicnum" -ne "$(xxd -p -l 10 $file)" ] && error="Магический номер файла не совпадает. Вы загрузили неправильный файл? $(xxd -p -l 10 $file) != $magicnum"
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# yaml-cli -i $POST_upfile -o /tmp/majestic.yaml # FIXME: sanitize
|
||||||
|
mv $file_path /etc/majestic.yaml
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
|
||||||
|
<% page_title="Обслуживание Majestic" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Резервная копия конфигурации</h3>
|
||||||
|
<p>Загрузите последний файл majestic.yaml, чтобы сохранить изменения, внесенные в конфигурацию по умолчанию.</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Backup" %>
|
||||||
|
<% button_submit "Скачать конфигурацию" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Восстановить конфигурацию</h3>
|
||||||
|
<p>Восстановите пользовательскую конфигурацию Majestic из сохраненной копии файла majestic.yaml.</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_hidden "action" "Restore" %>
|
||||||
|
<% field_file "mj_restore_file" "Файл резервного копирования" "majestic.yaml" %>
|
||||||
|
<% button_submit "Загрузить конфигурацию" "warning" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Посмотреть различия</h3>
|
||||||
|
<p>Сравните свежий файл majestic.yaml с тем, что идет в комплекте с прошивкой.</p>
|
||||||
|
<a class="btn btn-primary" href="majestic-config-compare.cgi">Проверить изменения</a>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Экспортировать как патч</h3>
|
||||||
|
<p>Экспорт изменений, внесенных в majestic.yaml, в виде файла исправления.</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Patch" %>
|
||||||
|
<% button_submit "Скачать файл патча" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Сброс</h3>
|
||||||
|
<% if [ "$(diff -q $config_file_fw $config_file)" ]; then %>
|
||||||
|
<p>Сбросьте конфигурацию Majestic в исходное состояние, которое поставляется с прошивкой.</p>
|
||||||
|
<% button_mj_reset %>
|
||||||
|
<% else %>
|
||||||
|
<p>Сбрасывать нечего. Последняя конфигурация Majestic не отличается от поставляемой с прошивкой.</p>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Изменения конфигурации Majestic" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 col-lg-9 col-xl-9 col-xxl-10">
|
||||||
|
<%
|
||||||
|
config_file=/etc/majestic.yaml
|
||||||
|
diff /rom$config_file $config_file >/tmp/majestic.patch
|
||||||
|
ex "cat /tmp/majestic.patch"
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-lg-3 col-xl-3 col-xxl-2">
|
||||||
|
<div class="d-grid d-sm-flex d-md-grid gap-2">
|
||||||
|
<a class="btn btn-secondary" href="texteditor.cgi?f=<%= $config_file %>">Редактировать конфигурацию как текст</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Конечные точки"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Видео</h3>
|
||||||
|
<dl>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/mjpeg</dt>
|
||||||
|
<dd>MJPEG video stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/video.mp4</dt>
|
||||||
|
<dd>fMP4 video stream.</dd>
|
||||||
|
<dt class="cp2cb">rtsp://username:password@<%= $network_address %>/stream=0</dt>
|
||||||
|
<dd>RTSP main stream (video0).</dd>
|
||||||
|
<dt class="cp2cb">rtsp://username:password@<%= $network_address %>/stream=1</dt>
|
||||||
|
<dd>RTSP substream (video1).</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/hls</dt>
|
||||||
|
<dd>HLS live-streaming in web browser.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/webrtc</dt>
|
||||||
|
<dd>WebRTC live-streaming in web browser.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/mjpeg.html</dt>
|
||||||
|
<dd>MJPEG & MP3 live-streaming in web browser.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Аудио</h3>
|
||||||
|
<dl>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.opus</dt>
|
||||||
|
<dd>Opus audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.pcm</dt>
|
||||||
|
<dd>Raw PCM audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.m4a</dt>
|
||||||
|
<dd>AAC audio stream.</dd>
|
||||||
|
<dt class="cp2cb ult">http://<%= $network_address %>/audio.mp3</dt>
|
||||||
|
<dd class="ult">MP3 audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.alaw</dt>
|
||||||
|
<dd>A-law compressed audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.ulaw</dt>
|
||||||
|
<dd>μ-law compressed audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/audio.g711a</dt>
|
||||||
|
<dd>G.711 A-law audio stream.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/play_audio</dt>
|
||||||
|
<dd>Play audio file on camera's speaker.<sup>1,3</sup>
|
||||||
|
<div class="small">Accepts POST requests with audio file as a parameter.</div></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Фотографии</h3>
|
||||||
|
<dl>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/image.jpg</dt>
|
||||||
|
<dd>Snapshot in JPEG format.<br>Optional parameters:<sup>2,4</sup>
|
||||||
|
<ul class="small">
|
||||||
|
<li>width, height - size of resulting image</li>
|
||||||
|
<li>qfactor - JPEG quality factor (1-99)</li>
|
||||||
|
<li>color2gray - convert to grayscale</li>
|
||||||
|
<li>crop - crop resulting image as 16x16x320x320</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/image.heif</dt>
|
||||||
|
<dd>Snapshot in HEIF format.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/image.yuv420</dt>
|
||||||
|
<dd>Snapshot in YUV420 format.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/image.dng</dt>
|
||||||
|
<dd>Snapshot in Adobe DNG format (raw).<sup>3</sup></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Ночной API</h3>
|
||||||
|
<dl>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/night/on</dt>
|
||||||
|
<dd>Turn on night mode.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/night/off</dt>
|
||||||
|
<dd>Turn off night mode.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/night/toggle</dt>
|
||||||
|
<dd>Toggle current night mode.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Мониторинг</h3>
|
||||||
|
<dl>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/api/v1/config.json</dt>
|
||||||
|
<dd>Actual Majestic config in JSON format.</dd>
|
||||||
|
<dt class="cp2cb">http://<%= $network_address %>/metrics</dt>
|
||||||
|
<dd>Node exporter for <a href="https://prometheus.io/">Prometheus</a>.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ol class="footnotes small">
|
||||||
|
<li class="text-body-secondary">Только процессоры HiSilicon и Goke.</li>
|
||||||
|
<li class="text-body-secondary">Только процессоры HiSilicon v2 и выше.</li>
|
||||||
|
<li class="text-body-secondary">E.g. <i>ffplay -ar 48000 -ac 1 -f s16le http://<%= $network_address %>/audio.pcm</i></li>
|
||||||
|
<li class="text-body-secondary">E.g. <i>http://<%= $network_address %>/image.jpg?width=640&height=480&qfactor=50&color2gray=1&crop=80x32x512x400</i></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p class="text-body-secondary">Доступны другие примеры <a href="https://github.com/OpenIPC/wiki/blob/master/en/majestic-streamer.md">вики</a>.</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function initializeCopyToClipboard() {
|
||||||
|
document.querySelectorAll(".cp2cb").forEach(function (element) {
|
||||||
|
element.title = "Click to copy to clipboard";
|
||||||
|
|
||||||
|
element.addEventListener("click", function (event) {
|
||||||
|
event.target.preventDefault;
|
||||||
|
event.target.animate({ color: 'red' }, 500);
|
||||||
|
|
||||||
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
|
navigator.clipboard.writeText(event.target.textContent).then(r => playChime(r));
|
||||||
|
} else {
|
||||||
|
let textArea = document.createElement("textarea");
|
||||||
|
textArea.value = event.target.textContent;
|
||||||
|
textArea.style.position = "fixed";
|
||||||
|
textArea.style.left = "-999999px";
|
||||||
|
textArea.style.top = "-999999px";
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
document.execCommand('copy') ? res() : rej();
|
||||||
|
textArea.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
window.onload = function () {
|
||||||
|
initializeCopyToClipboard();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,254 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Настройки Majestic"
|
||||||
|
mj=$(echo "$mj" | sed "s/ /_/g")
|
||||||
|
only="$GET_tab"; [ -z "$only" ] && only="system"
|
||||||
|
eval title="\$tT_mj_${only}"
|
||||||
|
|
||||||
|
# hide certain domains if not supported
|
||||||
|
if [ -n "$(eval echo "\$mj_hide_${only}" | sed -n "/\b${soc_family}\b/p")" ]; then
|
||||||
|
redirect_to "majestic-settings.cgi" "danger" "$title не поддерживается в вашей системе."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
mj_conf=/etc/majestic.yaml
|
||||||
|
temp_yaml=/tmp/majestic.yaml
|
||||||
|
|
||||||
|
# make a copy of the actual config into memory
|
||||||
|
cp -f $mj_conf $temp_yaml
|
||||||
|
|
||||||
|
OIFS=$IFS
|
||||||
|
IFS=$'\n' # make newlines the only separator
|
||||||
|
for yaml_param_name in $(printenv|grep POST_); do
|
||||||
|
form_field_name=$(echo $yaml_param_name | sed 's/^POST_mj_//')
|
||||||
|
key=".$(echo $form_field_name | cut -d= -f1 | sed 's/_/./g')"
|
||||||
|
|
||||||
|
# do not include helping fields into config
|
||||||
|
if [ "$key" = ".netip.password.plain" ] || [ "$key" = ".osd.corner" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
value="$(echo $form_field_name | cut -d= -f2)"
|
||||||
|
|
||||||
|
# normalization
|
||||||
|
# (that's why we can't have nice things)
|
||||||
|
case "$key" in
|
||||||
|
.image.rotate)
|
||||||
|
[ "0" = "$value" ] && value="none"
|
||||||
|
;;
|
||||||
|
.isp.antiFlicker)
|
||||||
|
[ "50Hz" = "$value" ] && value="50"
|
||||||
|
[ "60Hz" = "$value" ] && value="60"
|
||||||
|
;;
|
||||||
|
.motionDetect.visualize)
|
||||||
|
[ "true" = "$value" ] && yaml-cli -s ".osd.enabled" "true" -i $temp_yaml
|
||||||
|
;;
|
||||||
|
.osd.enabled)
|
||||||
|
[ "false" = "$value" ] && yaml-cli -s ".motionDetect.visualize" "false" -i $temp_yaml
|
||||||
|
;;
|
||||||
|
.system.webAdmin)
|
||||||
|
[ "true" = "$value" ] && value="enabled"
|
||||||
|
[ "false" = "$value" ] && value="disabled"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# read existing value
|
||||||
|
oldvalue=$(yaml-cli -g "$key" -i $temp_yaml)
|
||||||
|
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
# if no new value submitted but there is an existing value, delete the yaml_param_name
|
||||||
|
[ -n "$oldvalue" ] && yaml-cli -d $key -i "$temp_yaml" -o "$temp_yaml"
|
||||||
|
else
|
||||||
|
# if new value is submitted and it differs from the existing one, update the yaml_param_name
|
||||||
|
[ "$oldvalue" != "$value" ] && yaml-cli -s $key "$value" -i "$temp_yaml" -o "$temp_yaml"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
IFS=$OIFS
|
||||||
|
|
||||||
|
# update config if differs
|
||||||
|
[ -n "$(diff -q $temp_yaml $mj_conf)" ] && cp -f $temp_yaml $mj_conf
|
||||||
|
|
||||||
|
# clean up
|
||||||
|
rm $temp_yaml
|
||||||
|
|
||||||
|
# reload majestic
|
||||||
|
killall -1 majestic
|
||||||
|
|
||||||
|
redirect_to "$HTTP_REFERER"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<ul class="nav small mb-4 d-none d-lg-flex">
|
||||||
|
<%
|
||||||
|
mj=$(echo "$mj" | sed "s/ /_/g")
|
||||||
|
for _line in $mj; do
|
||||||
|
_parameter=${_line%%|*};
|
||||||
|
_param_name=${_parameter#.};
|
||||||
|
_param_domain=${_param_name%.*}
|
||||||
|
if [ "$_parameter_domain_old" != "$_param_domain" ]; then
|
||||||
|
# hide certain domains for certain familier
|
||||||
|
[ -n "$(eval echo "\$mj_hide_${_param_domain}" | sed -n "/\b${soc_family}\b/p")" ] && continue
|
||||||
|
# show certain domains only for certain vendors
|
||||||
|
[ -n "$(eval echo "\$mj_show_${_param_domain}_vendor")" ] && [ -z "$(eval echo "\$mj_show_${_param_domain}_vendor" | sed -n "/\b${soc_vendor}\b/p")" ] && continue
|
||||||
|
_parameter_domain_old="$_param_domain"
|
||||||
|
_css="class=\"nav-link\""; [ "$_param_domain" = "$only" ] && _css="class=\"nav-link active\" aria-current=\"true\""
|
||||||
|
echo "<li class=\"nav-item\"><a ${_css} href=\"majestic-settings.cgi?tab=${_param_domain}\">$(eval echo \$tT_mj_${_param_domain})</a></li>"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset _css; unset _param_domain; unset _line; unset _param_name; unset _parameter_domain_old; unset _parameter;
|
||||||
|
%>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3><%= $title %></h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<%
|
||||||
|
config=""
|
||||||
|
_mj2="$(echo "$mj" | sed "s/ /_/g" | grep -E "^\.$only")"
|
||||||
|
for line in $_mj2; do
|
||||||
|
# line: .isp.exposure|Sensor_exposure_time|µs|range|auto,1-500000|auto|From_1_to_500000.
|
||||||
|
yaml_param_name=${line%%|*} # => .isp.exposure
|
||||||
|
_param_name=${yaml_param_name#.} # => isp.exposure
|
||||||
|
_param_name=${_param_name//./_} # => isp_exposure
|
||||||
|
_param_name=${_param_name//-/_} # => isp_exposure
|
||||||
|
domain=${_param_name%%_*} # => isp
|
||||||
|
|
||||||
|
# hide certain domains if blacklisted
|
||||||
|
[ -n "$(eval echo "\$mj_hide_${domain}" | sed -n "/\b${soc_family}\b/p")" ] && continue
|
||||||
|
# hide certain parameters if blacklisted
|
||||||
|
[ -n "$(eval echo "\$mj_hide_${_param_name}_vendor" | sed -n "/\b${soc_vendor}\b/p")" ] && continue
|
||||||
|
[ -n "$(eval echo "\$mj_hide_${_param_name}" | sed -n "/\b${soc_family}\b/p")" ] && continue
|
||||||
|
# show certain domains only if whitelisted
|
||||||
|
[ -n "$(eval echo "\$mj_show_${domain}_vendor")" ] && [ -z "$(eval echo "\$mj_show_${domain}_vendor" | sed -n "/\b${soc_vendor}\b/p")" ] && continue
|
||||||
|
# show certain parameters only if whitelisted
|
||||||
|
[ -n "$(eval echo "\$mj_show_${_param_name}")" ] && [ -z "$(eval echo "\$mj_show_${_param_name}" | sed -n "/\b${soc_family}\b/p")" ] && continue
|
||||||
|
[ -n "$(eval echo "\$mj_show_${_param_name}_vendor")" ] && [ -z "$(eval echo "\$mj_show_${_param_name}_vendor" | sed -n "/\b${soc_vendor}\b/p")" ] && continue
|
||||||
|
# show certain parameters only in debug mode
|
||||||
|
[ -n "$(echo "$mj_hide_unless_debug" | sed -n "/\b${_param_name}\b/p")" ] && [ "0$debug" -lt "1" ] && continue
|
||||||
|
|
||||||
|
form_field_name=mj_${_param_name} # => mj_isp_exposure
|
||||||
|
line=${line#*|} # line: Sensor_exposure_time|µs|range|auto,1-500000|auto|From_1_to_500000.
|
||||||
|
label_text=${line%%|*} # => Sensor_exposure_time
|
||||||
|
label_text=${label_text//_/ } # => Sensor exposure time
|
||||||
|
line=${line#*|} # line: µs|range|auto,1-500000|auto|From_1_to_500000.
|
||||||
|
units=${line%%|*} # => µs
|
||||||
|
line=${line#*|} # line: range|auto,1-500000|auto|From_1_to_500000.
|
||||||
|
form_field_type=${line%%|*} # => range
|
||||||
|
line=${line#*|} # line: auto,1-500000|auto|From_1_to_500000.
|
||||||
|
options=${line%%|*} # => auto,1-500000
|
||||||
|
line=${line#*|} # line: auto|From_1_to_500000.
|
||||||
|
placeholder=${line%%|*} # => auto
|
||||||
|
line=${line#*|} # line: From_1_to_500000.
|
||||||
|
hint=$line # => From_1_to_500000.
|
||||||
|
hint=${hint//_/ } # => From 1 to 500000.
|
||||||
|
|
||||||
|
value="$(yaml-cli -g "$yaml_param_name")"
|
||||||
|
# FIXME: this is not how it should be done. Instead, Majestic should be reporting its true values.
|
||||||
|
# [ -z "$value" ] && value="$placeholder"
|
||||||
|
|
||||||
|
# assign yaml_param_name's value to a variable with yaml_param_name's form_field_name for form fields values
|
||||||
|
eval "$form_field_name=\"\$value\""
|
||||||
|
|
||||||
|
# hide some params in config
|
||||||
|
if [ "mj_netip_password_plain" != "$form_field_name" ]; then
|
||||||
|
config="${config}\n$(eval echo ${yaml_param_name}: \"\$$form_field_name\")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$form_field_type" in
|
||||||
|
boolean) field_switch "$form_field_name" "$label_text" "$hint" "$options";;
|
||||||
|
hidden) field_hidden "$form_field_name" "$label_text" "$hint";;
|
||||||
|
number) field_number "$form_field_name" "$label_text" "$options" "$hint";;
|
||||||
|
password) field_password "$form_field_name" "$label_text" "$hint";;
|
||||||
|
range) field_range "$form_field_name" "$label_text" "$options" "$hint";;
|
||||||
|
select) field_select "$form_field_name" "$label_text" "$options" "$hint";;
|
||||||
|
string) field_text "$form_field_name" "$label_text" "$hint" "$placeholder";;
|
||||||
|
*) echo "<span class=\"text-danger\">НЕИЗВЕСТНЫЙ ТИП ПОЛЯ ${form_field_type} ДЛЯ ${_name} С ОБОЗНАЧЕНИЕМ ${label_text}</span>";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
%>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let MD5 = function(d){return V(Y(X(d),8*d.length))};
|
||||||
|
function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}
|
||||||
|
function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}
|
||||||
|
function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}
|
||||||
|
function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}
|
||||||
|
function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}
|
||||||
|
function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}
|
||||||
|
function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}
|
||||||
|
function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}
|
||||||
|
function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}
|
||||||
|
function bit_rol(d,_){return d<<_|d>>>32-_}
|
||||||
|
function ord(str){return str.charCodeAt(0)}
|
||||||
|
function chr(n){return String.fromCharCode(n)}
|
||||||
|
|
||||||
|
function generateSofiaHash(text) {
|
||||||
|
let h = "";
|
||||||
|
let md5 = MD5(text);
|
||||||
|
for (let i = 0; i <= 7; i++) {
|
||||||
|
let n = (ord(md5[2*i]) + ord(md5[2*i+1])) % 62;
|
||||||
|
n += (n > 9) ? (n > 35) ? 61 : 55 : 48;
|
||||||
|
h += chr(n);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
<% if [ -d /etc/sensors/ ]; then %>
|
||||||
|
if ($("#mj_isp_sensorConfig")) {
|
||||||
|
const inp = $("#mj_isp_sensorConfig");
|
||||||
|
const sel = document.createElement("select");
|
||||||
|
sel.classList.add("form-select");
|
||||||
|
sel.name=inp.name;
|
||||||
|
sel.id=inp.id;
|
||||||
|
sel.options.add(new Option());
|
||||||
|
let opt;
|
||||||
|
<% for i in $(ls -1 /etc/sensors/*.ini); do %>
|
||||||
|
opt = new Option("<%= $i %>");
|
||||||
|
opt.selected = ("<%= $i %>" == inp.value);
|
||||||
|
sel.options.add(opt);
|
||||||
|
<% done %>
|
||||||
|
inp.replaceWith(sel);
|
||||||
|
}
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
$("#mj_osd_corner")?.addEventListener("change", (ev) => {
|
||||||
|
const padding = 16;
|
||||||
|
switch (ev.target.value) {
|
||||||
|
case "bl":
|
||||||
|
$("#mj_osd_posX").value = padding;
|
||||||
|
$("#mj_osd_posY").value = -(padding);
|
||||||
|
break;
|
||||||
|
case "br":
|
||||||
|
$("#mj_osd_posX").value = -(padding);
|
||||||
|
$("#mj_osd_posY").value = -(padding);
|
||||||
|
break;
|
||||||
|
case "tl":
|
||||||
|
$("#mj_osd_posX").value = padding;
|
||||||
|
$("#mj_osd_posY").value = padding;
|
||||||
|
break;
|
||||||
|
case "tr":
|
||||||
|
$("#mj_osd_posX").value = -(padding);
|
||||||
|
$("#mj_osd_posY").value = padding;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$("#mj_netip_enabled")?.addEventListener("change", (ev) => {
|
||||||
|
$("#mj_netip_user").required = ev.target.checked;
|
||||||
|
$("#mj_netip_password_plain").required = ev.target.checked;
|
||||||
|
})
|
||||||
|
|
||||||
|
$("#mj_netip_password_plain") && $("form").addEventListener("submit", (ev) => {
|
||||||
|
const pw = $("#mj_netip_password_plain").value.trim();
|
||||||
|
if (pw !== "") $("#mj_netip_password").value = generateSofiaHash(pw);
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,141 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
[ ! -f "/rom/${mj_bin_file}" ] && redirect_to '/' "danger" "Majestic не поддерживается в этой системе."
|
||||||
|
|
||||||
|
update_meta() {
|
||||||
|
# re-download metafile if older than 1 hour
|
||||||
|
mj_meta_url="http://openipc.s3-eu-west-1.amazonaws.com/majestic.${soc_family}.${fw_variant}.master.tar.meta"
|
||||||
|
|
||||||
|
if [ -f "$mj_meta_file" ]; then
|
||||||
|
mj_meta_file_timestamp=$(time_epoch "$(ls -lc --full-time $mj_meta_file | xargs | cut -d' ' -f6,7)")
|
||||||
|
mj_meta_file_expiration=$(( $(time_epoch) + 3600 ))
|
||||||
|
[ "$mj_meta_file_timestamp" -le "$mj_meta_file_expiration" ] && return
|
||||||
|
rm $mj_meta_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "200" = $(curl $mj_meta_url -s -f -w %{http_code} -o /dev/null) ] && curl -s $mj_meta_url -o $mj_meta_file
|
||||||
|
}
|
||||||
|
|
||||||
|
page_title="Majestic"
|
||||||
|
mj_meta_file=/tmp/mj_meta.txt
|
||||||
|
|
||||||
|
# NB! sizes are in allocated blocks.
|
||||||
|
mj_filesize_fw=$(ls -s $mj_bin_file | xargs | cut -d' ' -f1)
|
||||||
|
|
||||||
|
mj_bin_file_ol="${overlay_root}${mj_bin_file}"
|
||||||
|
[ -f "$mj_bin_file_ol" ] && mj_filesize_ol=$(ls -s $mj_bin_file_ol | xargs | cut -d' ' -f1)
|
||||||
|
|
||||||
|
free_space=$(df | grep /overlay | xargs | cut -d' ' -f4)
|
||||||
|
available_space=$(( ${free_space:=0} + ${mj_filesize_ol:=0} - 1 ))
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
rmmj)
|
||||||
|
[ -f "$mj_bin_file_ol" ] && rm $mj_bin_file_ol && mount -oremount /
|
||||||
|
redirect_back "success" "Majestic вернулся к базовой версии."
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
[ -z "$network_gateway" ] && redirect_to "danger" "Для обновления требуется подключение к интернету!"
|
||||||
|
|
||||||
|
update_meta
|
||||||
|
mj_filesize_new=$(( ($(cat $mj_meta_file | sed -n 2p) + 1024) / 1024 ))
|
||||||
|
[ "$mj_filesize_new" -gt "$available_space" ] && redirect_back "danger" "Недостаточно места для обновления Majestic. ${mj_filesize_new} КБ > ${available_space} КБ."
|
||||||
|
|
||||||
|
curl --silent --insecure --location -o - http://openipc.s3-eu-west-1.amazonaws.com/majestic.${soc_family}.${fw_variant}.master.tar.bz2 | bunzip2 | tar -x ./majestic -C /usr/bin/
|
||||||
|
[ $? -ne 0 ] && redirect_back "error" "Недостаточно места для обновления Majestic."
|
||||||
|
redirect_to "reboot.cgi"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
mj_version_fw=$(/rom${mj_bin_file} -v)
|
||||||
|
mj_version_ol="<span class=\"text-secondary\">- не устанавливается в оверлее -</span>"
|
||||||
|
[ -f "$mj_bin_file_ol" ] && mj_version_ol=$($mj_bin_file_ol -v)
|
||||||
|
|
||||||
|
if [ -n "$network_gateway" ]; then
|
||||||
|
update_meta
|
||||||
|
if [ -f "$mj_meta_file" ]; then
|
||||||
|
# parse version, date and file size
|
||||||
|
if [ "$(wc -l $mj_meta_file | cut -d' ' -f1)" = "1" ]; then
|
||||||
|
mj_filesize_new=$(sed -n 1p $mj_meta_file)
|
||||||
|
else
|
||||||
|
mj_version_new=$(sed -n 1p $mj_meta_file)
|
||||||
|
mj_filesize_new=$(sed -n 2p $mj_meta_file)
|
||||||
|
fi
|
||||||
|
# NB! size in bytes, but since blocks are 1024 bytes each, we are safe here for now.
|
||||||
|
mj_filesize_new=$(( ($mj_filesize_new + 1024) / 1024 )) # Rounding up by priming, since $(()) sucks at floats.
|
||||||
|
else
|
||||||
|
mj_version_new="unavailable"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
mj_version_new="<span class=\"text-danger\">- нет доступа к сегменту S3 -</span>"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Version</h3>
|
||||||
|
<dl class="list small">
|
||||||
|
<dt>Bundled</dt>
|
||||||
|
<dd><%= $mj_version_fw %></dd>
|
||||||
|
<dt>In overlay</dt>
|
||||||
|
<dd><%= $mj_version_ol %></dd>
|
||||||
|
<dt>On GitHub</dt>
|
||||||
|
<dd><%= $mj_version_new %></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Конфигурация</h3>
|
||||||
|
<% if [ -z "$(diff /rom/etc/majestic.yaml /etc/majestic.yaml)" ]; then %>
|
||||||
|
<p>Majestic использует оригинальную конфигурацию.</p>
|
||||||
|
<p><a href="majestic-settings.cgi">Внести изменения.</a></p>
|
||||||
|
<% else %>
|
||||||
|
<p>Majestic использует индивидуальную конфигурацию.</p>
|
||||||
|
<p><a href="majestic-config-compare.cgi" class="btn btn-primary">Показать различия</a></p>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<% if [ -n "$network_gateway" ]; then %>
|
||||||
|
<h3>Update</h3>
|
||||||
|
<% if [ "$mj_version_new" = "$mj_version_ol" ] || [ -z "$mj_version_ol" -a "$mj_version_new" = "$mj_version_fw" ]; then %>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<p class="mb-1"><b>Нечего обновлять.</b></p>
|
||||||
|
<p class="mb-0">Последняя версия уже установлена.</p>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<% if [ -f "$mj_meta_file" ]; then %>
|
||||||
|
<% if [ "$mj_filesize_new" -le "$available_space" ]; then %>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Обновление" %>
|
||||||
|
<% button_submit "Установить обновление" "warning" %>
|
||||||
|
</form>
|
||||||
|
<% else %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-1"><b>Недостаточно места для обновления Majestic!</b></p>
|
||||||
|
<p class="mb-0">Обновление требует <%= $mj_filesize_new %>KБ, но только <%= $available_space %>KБ доступно
|
||||||
|
<% if [ "$mj_filesize_ol" -ge "1" ]; then %>
|
||||||
|
(<%= $free_space %>KБ нераспределенного пространства плюс <%= ${mj_filesize_ol:=0} %>KБ размер Majestic, установленного в оверлее)
|
||||||
|
<% fi %>
|
||||||
|
.</p>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
<% fi %>
|
||||||
|
<% fi %>
|
||||||
|
<% else %>
|
||||||
|
<p class="alert alert-danger">Для обновления требуется доступ к Amazon S3.</p>
|
||||||
|
<% fi %>
|
||||||
|
<% if [ -f "$mj_bin_file_ol" ]; then %>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<p>Более поздняя версия Majestic найдена в разделе оверлея. Занимает <%= $mj_filesize_ol %> KБ места на диске.</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "rmmj" %>
|
||||||
|
<% button_submit "Вернуться к базовой версии" "warning" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="socks5"
|
||||||
|
page_title="SOCKS5 proxy"
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
:>$tmp_file
|
||||||
|
for v in enabled server port username password; do
|
||||||
|
eval echo "${plugin}_${v}=\\\"\$POST_${plugin}_${v}\\\"" >>$tmp_file
|
||||||
|
done
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
include $config_file
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "update" %>
|
||||||
|
<% field_text "socks5_host" "Хост SOCKS5" %>
|
||||||
|
<% field_number "socks5_port" "Порт SOCKS5 " "1080" %>
|
||||||
|
<% field_text "socks5_username" "Имя пользователя SOCKS5" %>
|
||||||
|
<% field_password "socks5_password" "Пароль SOCKS5" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="Сеть"
|
||||||
|
page_title="Сетевые настройки"
|
||||||
|
params="address dhcp dns_1 dns_2 gateway hostname netmask interface_type wifi_modules wifi_ssid wifi_password wifi_power_pin"
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
changemac)
|
||||||
|
if echo "$POST_mac_address" | grep -Eiq '^([0-9a-f]{2}[:-]){5}([0-9a-f]{2})$'; then
|
||||||
|
fw_setenv ethaddr $POST_mac_address
|
||||||
|
update_caminfo
|
||||||
|
redirect_to "reboot.cgi"
|
||||||
|
else
|
||||||
|
redirect_back "warning" "${POST_mac_address} является недопустимым MAC-адресом."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
reset)
|
||||||
|
/usr/sbin/sysreset.sh -n
|
||||||
|
redirect_back
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
if [ "false" = "$network_dhcp" ]; then
|
||||||
|
network_mode="static"
|
||||||
|
[ -z "$network_default_interface" ] && flash_append "danger" "Сетевой интерфейс по умолчанию не может быть пустым." && error=1
|
||||||
|
[ -z "$network_address" ] && flash_append "danger" "IP-адрес не может быть пустым." && error=1
|
||||||
|
[ -z "$network_netmask" ] && flash_append "danger" "Маска сети не может быть пустой." && error=1
|
||||||
|
[ -z "$network_interface_type" ] && flash_append "danger" "Тип сетевого интерфейса не может быть пустым." && error=1
|
||||||
|
# [ -z "$network_gateway" ] && flash_append "danger" "IP-адрес шлюза не может быть пустым." && error=1
|
||||||
|
# [ -z "$network_dns_1" ] && flash_append "danger" "Адрес сервера имен не может быть пустым." && error=1
|
||||||
|
# [ -z "$network_dns_2" ] && flash_append "danger" "Адрес сервера имен не может быть пустым." && error=1
|
||||||
|
else
|
||||||
|
network_mode="dhcp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
command="setnetiface.sh"
|
||||||
|
command="${command} -i $network_default_interface"
|
||||||
|
command="${command} -m $network_mode"
|
||||||
|
command="${command} -n $network_hostname"
|
||||||
|
command="${command} -t $network_interface_type"
|
||||||
|
|
||||||
|
if [ "wlan0" = "$network_default_interface" ]; then
|
||||||
|
command="${command} -s $network_wifi_ssid"
|
||||||
|
command="${command} -p $network_wifi_password"
|
||||||
|
command="${command} -k $network_wifi_modules"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "dhcp" != "$network_mode" ]; then
|
||||||
|
command="${command} -a $network_address"
|
||||||
|
command="${command} -n $network_netmask"
|
||||||
|
command="${command} -g $network_gateway"
|
||||||
|
command="${command} -d $network_dns_1"
|
||||||
|
[ -n "$network_dns_2" ] && command="${command},${network_dns_2}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$command" >>/tmp/webui.log
|
||||||
|
eval "$command" >/dev/null 2>&1
|
||||||
|
|
||||||
|
/etc/init.d/S40network restart >/dev/null
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "Настройки сети успешно обновлены."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col col-md-6 col-lg-4 mb-4">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Обновить" %>
|
||||||
|
<% field_text "network_hostname" "Имя устройства" %>
|
||||||
|
<% field_select "network_default_interface" "Сетевой интерфейс по умолчанию" "$network_interfaces" %>
|
||||||
|
<% field_select "network_interface_type" "Tип сетевого интерфейса" "eth wifi ppp usb wg" %>
|
||||||
|
<% field_text "network_wifi_modules" "Wi-Fi модули" %>
|
||||||
|
<% field_text "network_wifi_ssid" "WiFi SSID" %>
|
||||||
|
<% field_text "network_wifi_password" "WiFi пароль" %>
|
||||||
|
|
||||||
|
<% field_switch "network_dhcp" "Использовать DHCP" %>
|
||||||
|
<% field_text "network_address" "IP-адрес" %>
|
||||||
|
<% field_text "network_netmask" "Маска подсети" %>
|
||||||
|
<% field_text "network_gateway" "Шлюз по умолчанию" %>
|
||||||
|
<% field_text "network_dns_1" "DNS 1" %>
|
||||||
|
<% field_text "network_dns_2" "DNS 2" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alert alert-danger mt-4">
|
||||||
|
<h5>Сбросить конфигурацию сети</h5>
|
||||||
|
<p>Восстановите файл конфигурации в комплекте с прошивкой. Все изменения конфигурации по умолчанию будут потеряны!</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_hidden "action" "Перезагрузка" %>
|
||||||
|
<% button_submit "Сбросить настройки" "danger" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function toggleDhcp() {
|
||||||
|
const c = $('#network_dhcp[type=checkbox]').checked;
|
||||||
|
const ids = ['network_address','network_netmask','network_gateway','network_dns_1','network_dns_2'];
|
||||||
|
ids.forEach(id => {
|
||||||
|
$('#' + id).disabled = c;
|
||||||
|
let el = $('#' + id + '_wrap');
|
||||||
|
c ? el.classList.add('d-none') : el.classList.remove('d-none');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleIface() {
|
||||||
|
const ids = ['network_wifi_modules','network_wifi_ssid','network_wifi_password'];
|
||||||
|
if ($('#network_default_interface').value == 'wlan0') {
|
||||||
|
ids.forEach(id => $('#' + id + '_wrap').classList.remove('d-none'));
|
||||||
|
} else {
|
||||||
|
ids.forEach(id => $('#' + id + '_wrap').classList.add('d-none'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#network_default_interface').addEventListener('change', toggleIface);
|
||||||
|
$('#network_dhcp[type=checkbox]').addEventListener('change', toggleDhcp);
|
||||||
|
|
||||||
|
toggleIface();
|
||||||
|
toggleDhcp();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
case "$POST_mode" in
|
||||||
|
on)
|
||||||
|
curl -s http://127.0.0.1/night/on
|
||||||
|
;;
|
||||||
|
off)
|
||||||
|
curl -s http://127.0.0.1/night/off
|
||||||
|
;;
|
||||||
|
toggle)
|
||||||
|
curl -s http://127.0.0.1/night/toggle
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
header_ok
|
||||||
|
%>
|
|
@ -0,0 +1,814 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%
|
||||||
|
IFS_ORIG=$IFS
|
||||||
|
|
||||||
|
# tag "tag" "text" "css" "extras"
|
||||||
|
tag() {
|
||||||
|
local _t="$1"
|
||||||
|
local _n="$2"
|
||||||
|
local _c="$3"
|
||||||
|
local _x="$4"
|
||||||
|
[ -n "$_c" ] && _c=" class=\"${_c}\""
|
||||||
|
[ -n "$_x" ] && _x=" ${_x}"
|
||||||
|
echo "<${_t}${_c}${_x}>${_n}</${_t}>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A "tag" "classes" "extras"
|
||||||
|
A() {
|
||||||
|
local _c="$2"; [ -n "$_c" ] && _c=" class=\"${_c}\""
|
||||||
|
local _x="$3"; [ -n "$_x" ] && _x=" ${_x}"
|
||||||
|
echo "<${1}${_c}${_x}>"
|
||||||
|
}
|
||||||
|
|
||||||
|
Z() {
|
||||||
|
echo "</${1}>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# tag "text" "classes" "extras"
|
||||||
|
div() { tag "div" "$1" "$2" "$3"; }
|
||||||
|
h1() { tag "h1" "$1" "$2" "$3"; }
|
||||||
|
h2() { tag "h2" "$1" "$2" "$3"; }
|
||||||
|
h3() { tag "h3" "$1" "$2" "$3"; }
|
||||||
|
h4() { tag "h4" "$1" "$2" "$3"; }
|
||||||
|
h5() { tag "h5" "$1" "$2" "$3"; }
|
||||||
|
h6() { tag "h6" "$1" "$2" "$3"; }
|
||||||
|
label() { tag "label" "$1" "$2" "$3"; }
|
||||||
|
li() { tag "li" "$1" "$2" "$3"; }
|
||||||
|
p() { tag "p" "$1" "$2" "$3"; }
|
||||||
|
span() { tag "span" "$1" "$2" "$3"; }
|
||||||
|
|
||||||
|
div_() { A "div" "$1" "$2"; }
|
||||||
|
_div() { Z "div"; }
|
||||||
|
span_() { A "span" "$1" "$2"; }
|
||||||
|
_span() { Z "span"; }
|
||||||
|
|
||||||
|
# alert "text" "type" "extras"
|
||||||
|
alert() {
|
||||||
|
echo "<div class=\"alert alert-${2}\" ${3}>${1}</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# time_gmt "format" "date"
|
||||||
|
time_gmt() {
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
TZ=GMT0 date +"$1" --date="${2}"
|
||||||
|
else
|
||||||
|
TZ=GMT0 date +"$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
time_epoch() {
|
||||||
|
time_gmt "%s" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
time_http() {
|
||||||
|
time_gmt "%a, %d %b %Y %T %Z" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_download() {
|
||||||
|
echo "<a href=\"dl2.cgi?log=${1}\" class=\"btn btn-primary\">Скачать лог</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_mj_backup() {
|
||||||
|
echo "<form action=\"majestic-config-actions.cgi\" method=\"post\">" \
|
||||||
|
"<input type=\"hidden\" name=\"action\" value=\"backup\">"
|
||||||
|
button_submit "Восстановить настройки"
|
||||||
|
echo "</form>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_mj_reset() {
|
||||||
|
echo "<form action=\"majestic-config-actions.cgi\" method=\"post\">" \
|
||||||
|
"<input type=\"hidden\" name=\"action\" value=\"reset\">"
|
||||||
|
button_submit "Перезапустить Majestic" "danger"
|
||||||
|
echo "</form>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_reboot() {
|
||||||
|
echo "<form action=\"reboot.cgi\" method=\"post\">" \
|
||||||
|
"<input type=\"hidden\" name=\"action\" value=\"reboot\">"
|
||||||
|
button_submit "Перезагрузить камеру" "danger"
|
||||||
|
echo "</form>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_refresh() {
|
||||||
|
echo "<a href=\"${REQUEST_URI}\" class=\"btn btn-primary refresh\">Обновить</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_reset_firmware() {
|
||||||
|
echo "<form action=\"firmware-reset.cgi\" method=\"post\">" \
|
||||||
|
"<input type=\"hidden\" name=\"action\" value=\"reset\">"
|
||||||
|
button_submit "Перезагрузить прошивку" "danger"
|
||||||
|
echo "</form>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_restore_from_rom() {
|
||||||
|
local file=$1
|
||||||
|
[ ! -f "/rom/${file}" ] && return
|
||||||
|
if [ -z "$(diff "/rom/${file}" "${file}")" ]; then
|
||||||
|
echo "<p class=\"small fst-italic\">Файл соответствует версии в ПЗУ.</p>"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "<p><a class=\"btn btn-danger\" href=\"restore.cgi?f=${file}\">Заменить ${file} его версией из ПЗУ</a></p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# button_submit "text" "type" "extras"
|
||||||
|
button_submit() {
|
||||||
|
local _t="$1"; [ -z "$_t" ] && _t="Сохранить изменения"
|
||||||
|
local _c="$2"; [ -z "$_c" ] && _c="primary"
|
||||||
|
local _x="$3"; [ -z "$_x" ] && _x=" ${_x}"
|
||||||
|
echo "<div class=\"mt-2\"><input type=\"submit\" class=\"btn btn-${_c}\"${_x} value=\"${_t}\"></div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
button_webui_log() {
|
||||||
|
[ -f "/tmp/webui.log" ] &&
|
||||||
|
link_to "Скачать файл журнала" "dl.cgi?file=/tmp/webui.log"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_file_exist() {
|
||||||
|
[ ! -f "$1" ] &&
|
||||||
|
redirect_back "danger" "Файл ${1} не найден"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_password() {
|
||||||
|
_safepage="/cgi-bin/webui-settings.cgi"
|
||||||
|
[ "0${debug}" -ge "1" ] && return
|
||||||
|
[ -z "$REQUEST_URI" ] || [ "$REQUEST_URI" = "${_safepage}" ] && return
|
||||||
|
if [ ! -f /etc/shadow- ] || [ -z $(grep root /etc/shadow- | cut -d: -f2) ]; then
|
||||||
|
redirect_to "${_safepage}" "danger" "Вы должны установить свой собственный безопасный пароль!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
e() {
|
||||||
|
echo -e -n "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ex() {
|
||||||
|
# NB! $() forks process and stalls output.
|
||||||
|
echo "<div class=\"${2}\">"
|
||||||
|
echo "<h6># ${1}</h6><pre class=\"small\">"
|
||||||
|
eval "$1" | sed "s/&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g"
|
||||||
|
echo "</pre>"
|
||||||
|
echo "</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_checkbox "name" "label" "hint"
|
||||||
|
field_checkbox() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${1}</span>"
|
||||||
|
local _h=$3
|
||||||
|
local _v=$(t_value "$1")
|
||||||
|
[ -z "$_v" ] && _v="false"
|
||||||
|
echo "<p class=\"boolean form-check\">" \
|
||||||
|
"<input type=\"hidden\" id=\"${1}-false\" name=\"${1}\" value=\"false\">" \
|
||||||
|
"<input type=\"checkbox\" name=\"${1}\" id=\"${1}\" value=\"true\" class=\"form-check-input\"$(t_checked "true" "$_v")>" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary d-block mb-2\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_file "name" "label" "hint"
|
||||||
|
field_file() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${1}</span>"
|
||||||
|
local _h=$3
|
||||||
|
echo "<p class=\"file\">" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>" \
|
||||||
|
"<input type=\"file\" id=\"${1}\" name=\"${1}\" class=\"form-control\">"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_hidden "name" "value"
|
||||||
|
field_hidden() {
|
||||||
|
# do we need id here? id=\"${1}\". We do for netip password!
|
||||||
|
echo "<input type=\"hidden\" name=\"${1}\" id=\"${1}\" value=\"${2}\" class=\"form-hidden\">"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_number "name" "label" "range" "hint"
|
||||||
|
field_number() {
|
||||||
|
local _n=$1
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${1}</span>"
|
||||||
|
local _r=$3 # min,max,step,button
|
||||||
|
local _mn=$(echo "$_r" | cut -d, -f1)
|
||||||
|
local _mx=$(echo "$_r" | cut -d, -f2)
|
||||||
|
local _st=$(echo "$_r" | cut -d, -f3)
|
||||||
|
local _ab=$(echo "$_r" | cut -d, -f4)
|
||||||
|
local _h=$4
|
||||||
|
local _v=$(t_value "$_n")
|
||||||
|
local _vr=$_v
|
||||||
|
[ -n "$_ab" ] && [ "$_ab" = "$_v" ] && _vr=$(( ( $_mn + $_mx ) / 2 ))
|
||||||
|
echo "<p class=\"number\">" \
|
||||||
|
"<label class=\"form-label\" for=\"${_n}\">${_l}</label>" \
|
||||||
|
"<span class=\"input-group\">"
|
||||||
|
# NB! no name on checkbox, since we don't want its data submitted
|
||||||
|
[ -n "$_ab" ] && echo "<label class=\"input-group-text\" for=\"${_n}-auto\">${_ab}" \
|
||||||
|
"<input type=\"checkbox\" class=\"form-check-input auto-value ms-1\" id=\"${_n}-auto\"" \
|
||||||
|
" data-for=\"${_n}\" data-value=\"${_vr}\" $(t_checked "$_ab" "$_v")>" \
|
||||||
|
"</label>"
|
||||||
|
echo "<input type=\"number\" id=\"${_n}\" name=\"${_n}\" class=\"form-control text-end\"" \
|
||||||
|
" value=\"${_vr}\" min=\"${_mn}\" max=\"${_mx}\" step=\"${_st}\">" \
|
||||||
|
"</span>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_password "name" "label" "hint"
|
||||||
|
field_password() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${1}</span>"
|
||||||
|
local _h=$3
|
||||||
|
local _v=$(t_value "$1")
|
||||||
|
echo "<p class=\"password\" id=\"${1}_wrap\">" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>" \
|
||||||
|
"<span class=\"input-group\">" \
|
||||||
|
"<input type=\"password\" id=\"${1}\" name=\"${1}\" class=\"form-control\" value=\"${_v}\" placeholder=\"P@s$W0rD!\">" \
|
||||||
|
"<label class=\"input-group-text\">" \
|
||||||
|
"<input type=\"checkbox\" class=\"form-check-input me-1\" data-for=\"${1}\"> Показать" \
|
||||||
|
"</label>" \
|
||||||
|
"</span>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_range "name" "label" "range" "hint"
|
||||||
|
field_range() {
|
||||||
|
local _n=$1
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$_n")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${_n}</span>"
|
||||||
|
local _r=$3 # min,max,step,button
|
||||||
|
local _mn=$(echo "$_r" | cut -d, -f1)
|
||||||
|
local _mx=$(echo "$_r" | cut -d, -f2)
|
||||||
|
local _st=$(echo "$_r" | cut -d, -f3)
|
||||||
|
local _ab=$(echo "$_r" | cut -d, -f4)
|
||||||
|
local _h=$4
|
||||||
|
local _v=$(t_value "$_n")
|
||||||
|
local _vr=$_v
|
||||||
|
[ -z "$_vr" -o "$_ab" = "$_vr" ] && _vr=$(( ( $_mn + $_mx ) / 2 ))
|
||||||
|
echo "<p class=\"range\" id=\"${_n}_wrap\">" \
|
||||||
|
"<label class=\"form-label\" for=\"${_n}\">${_l}</label>" \
|
||||||
|
"<span class=\"input-group\">"
|
||||||
|
# NB! no name on checkbox, since we don't want its data submitted
|
||||||
|
[ -n "$_ab" ] && echo "<label class=\"input-group-text\" for=\"${_n}-auto\">${_ab}" \
|
||||||
|
"<input type=\"checkbox\" class=\"form-check-input auto-value ms-1\" id=\"${_n}-auto\"" \
|
||||||
|
" data-for=\"${_n}\" data-value=\"${_vr}\" $(t_checked "$_ab" "$_v")>" \
|
||||||
|
"</label>"
|
||||||
|
# Input that holds the submitting value.
|
||||||
|
echo "<input type=\"hidden\" name=\"${_n}\" id=\"${_n}\" value=\"${_v}\">"
|
||||||
|
# NB! no name on range, since we don't want its data submitted
|
||||||
|
echo "<input type=\"range\" class=\"form-control form-range\" id=\"${_n}-range\"" \
|
||||||
|
"value=\"${_vr}\" min=\"${_mn}\" max=\"${_mx}\" step=\"${_st}\">"
|
||||||
|
echo "<span class=\"input-group-text show-value\" id=\"${_n}-show\">${_vr}</span>" \
|
||||||
|
"</span>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_select "name" "label" "options" "hint" "units"
|
||||||
|
field_select() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">${1}</span>"
|
||||||
|
local _o=$3
|
||||||
|
_o=${_o//,/ }
|
||||||
|
local _h=$4
|
||||||
|
local _u=$5
|
||||||
|
echo "<p class=\"select\" id=\"${1}_wrap\">" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>" \
|
||||||
|
"<select class=\"form-select\" id=\"${1}\" name=\"${1}\">"
|
||||||
|
[ -z "$(t_value "$1")" ] && echo "<option value=\"\">Выберите из доступных вариантов</option>"
|
||||||
|
for o in $_o; do
|
||||||
|
_v="${o%:*}"
|
||||||
|
_n="${o#*:}"
|
||||||
|
[ "$1" != "mj_isp_sensorConfig" ] && _n=${_n//_/ }
|
||||||
|
echo -n "<option value=\"${_v}\""
|
||||||
|
[ "$(t_value "$1")" = "$_v" ] && echo -n " selected"
|
||||||
|
echo ">${_n}</option>"
|
||||||
|
unset _v; unset _n
|
||||||
|
done
|
||||||
|
echo "</select>"
|
||||||
|
[ -n "$_u" ] && echo "<span class=\"input-group-text\">${_u}</span>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_swith "name" "label" "hint" "options"
|
||||||
|
field_switch() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">$1</span>"
|
||||||
|
local _v=$(t_value "$1"); [ -z "$_v" ] && _v="false"
|
||||||
|
local _h="$3"
|
||||||
|
local _o=$4; [ -z "$_o" ] && _o="true,false"
|
||||||
|
local _o1=$(echo "$_o" | cut -d, -f1)
|
||||||
|
local _o2=$(echo "$_o" | cut -d, -f2)
|
||||||
|
echo "<p class=\"boolean\">" \
|
||||||
|
"<span class=\"form-check form-switch\">" \
|
||||||
|
"<input type=\"hidden\" id=\"${1}-false\" name=\"${1}\" value=\"${_o2}\">" \
|
||||||
|
"<input type=\"checkbox\" id=\"${1}\" name=\"${1}\" value=\"${_o1}\" role=\"switch\"" \
|
||||||
|
" class=\"form-check-input\"$(t_checked "$_o1" "$_v")>" \
|
||||||
|
"<label for=\"$1\" class=\"form-check-label\">${_l}</label>" \
|
||||||
|
"</span>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_text "name" "label" "hint" "placeholder"
|
||||||
|
field_text() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">$1</span>"
|
||||||
|
local _v="$(t_value "$1")"
|
||||||
|
local _h="$3"
|
||||||
|
local _p="$4"
|
||||||
|
echo "<p class=\"string\" id=\"${1}_wrap\">" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>" \
|
||||||
|
"<input type=\"text\" id=\"${1}\" name=\"${1}\" class=\"form-control\" value=\"${_v}\" placeholder=\"${_p}\">"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# field_textarea "name" "label" "hint"
|
||||||
|
field_textarea() {
|
||||||
|
local _l=$2
|
||||||
|
[ -z "$_l" ] && _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="<span class=\"bg-warning\">$1</span>"
|
||||||
|
local _v=$(t_value "$1")
|
||||||
|
local _h=$3
|
||||||
|
echo "<p class=\"textarea\" id=\"${1}_wrap\">" \
|
||||||
|
"<label for=\"${1}\" class=\"form-label\">${_l}</label>" \
|
||||||
|
"<textarea id=\"${1}\" name=\"${1}\" class=\"form-control\">${_v}</textarea>"
|
||||||
|
[ -n "$_h" ] && echo "<span class=\"hint text-secondary\">${_h}</span>"
|
||||||
|
echo "</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_append() {
|
||||||
|
echo "$1:$2" >>"$flash_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_delete() {
|
||||||
|
:>"$flash_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_read() {
|
||||||
|
[ ! -f "$flash_file" ] && return
|
||||||
|
[ -z "$(cat $flash_file)" ] && return
|
||||||
|
local _c
|
||||||
|
local _m
|
||||||
|
local _l
|
||||||
|
OIFS="$IFS"
|
||||||
|
IFS=$'\n'
|
||||||
|
for _l in $(cat "$flash_file"); do
|
||||||
|
_c="$(echo $_l | cut -d':' -f1)"
|
||||||
|
_m="$(echo $_l | cut -d':' -f2-)"
|
||||||
|
echo "<div class=\"alert alert-${_c} alert-dismissible fade show\" role=\"alert\">" \
|
||||||
|
"${_m}" \
|
||||||
|
"<button type=\"button\" class=\"btn btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>" \
|
||||||
|
"</div>"
|
||||||
|
done
|
||||||
|
IFS=$OIFS
|
||||||
|
flash_delete
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_save() {
|
||||||
|
echo "${1}:${2}" >$flash_file
|
||||||
|
}
|
||||||
|
|
||||||
|
get_soc_temp() {
|
||||||
|
[ "true" = "$soc_has_temp" ] && soc_temp=$(ipcinfo --temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
header_ok() {
|
||||||
|
echo "HTTP/1.1 200 OK
|
||||||
|
Content-type: application/json; charset=UTF-8
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
|
||||||
|
{}"
|
||||||
|
}
|
||||||
|
|
||||||
|
html_title() {
|
||||||
|
[ -n "$page_title" ] && echo -n "$page_title"
|
||||||
|
[ -n "$title" ] && echo -n ": $title"
|
||||||
|
echo -n " - Мелдана"
|
||||||
|
}
|
||||||
|
|
||||||
|
# label "name" "classes" "extras" "units"
|
||||||
|
label() {
|
||||||
|
local _c="form-label"
|
||||||
|
[ -n "$2" ] && _c="${_c} ${2}"
|
||||||
|
local _l="$(t_label "$1")"
|
||||||
|
[ -z "$_l" ] && _l="$1" && _c="${_c} bg-warning"
|
||||||
|
local _x="$3"
|
||||||
|
[ -n "$_x" ] && _x=" ${_x}"
|
||||||
|
local _u="$4"
|
||||||
|
[ -n "$_u" ] && _l="${_l}, <span class=\"units text-secondary x-small\">$_u</span>"
|
||||||
|
echo "<label for=\"${1}\" class=\"${_c}\"${_x}>${_l}</label>"
|
||||||
|
}
|
||||||
|
|
||||||
|
link_to() {
|
||||||
|
echo "<a href=\"${2}\">${1}</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
load_plugins() {
|
||||||
|
local i
|
||||||
|
local n
|
||||||
|
local p
|
||||||
|
for i in $(ls -1 plugin-*); do
|
||||||
|
# get plugin name
|
||||||
|
p="$(sed -r -n '/^plugin=/s/plugin="(.*)"/\1/p' $i)"
|
||||||
|
|
||||||
|
# hide unsupported plugins
|
||||||
|
[ "$p" = "mqtt" ] && [ ! -f /usr/bin/mosquitto_pub ] && continue
|
||||||
|
[ "$p" = "telegrambot" ] && [ ! -f /usr/bin/jsonfilter ] && continue
|
||||||
|
[ "$p" = "zerotier" ] && [ ! -f /usr/sbin/zerotier-cli ] && continue
|
||||||
|
|
||||||
|
# get plugin description
|
||||||
|
n="$(sed -r -n '/^plugin_name=/s/plugin_name="(.*)"/\1/p' $i)"
|
||||||
|
|
||||||
|
# check if plugin is enabled
|
||||||
|
echo -n "<li><a class=\"dropdown-item"
|
||||||
|
grep -q "^${p}_enabled=\"true\"" ${ui_config_dir}/${p}.conf && echo -n " plugin-enabled"
|
||||||
|
echo "\" href=\"${i}\">${n}</a></li>"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo $1 >/tmp/webui.log
|
||||||
|
}
|
||||||
|
|
||||||
|
majestic_diff() {
|
||||||
|
config_file=/etc/majestic.yaml
|
||||||
|
diff /rom$config_file $config_file >/tmp/majestic.patch
|
||||||
|
cat /tmp/majestic.patch
|
||||||
|
}
|
||||||
|
|
||||||
|
# select_option "name" "value"
|
||||||
|
select_option() {
|
||||||
|
local _v=$2
|
||||||
|
[ -z "$_v" ] && _v=$1
|
||||||
|
local _s=""
|
||||||
|
[ "$_v" = eval \$$_v ] && $s=" selected"
|
||||||
|
echo "<option value=\"${_v}\"${_s}>${1}</label>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# pre "text" "classes" "extras"
|
||||||
|
pre() {
|
||||||
|
# replace <, >, &, ", and ' with HTML entities
|
||||||
|
tag "pre" "$(echo -e "$1" | sed "s/&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g")" "$2" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
preview() {
|
||||||
|
local refresh_rate=10
|
||||||
|
[ -n "$1" ] && refresh_rate=$1
|
||||||
|
if [ "true" = "$(yaml-cli -g .jpeg.enabled)" ]; then
|
||||||
|
echo "<canvas id=\"preview\" style=\"background:gray url(/a/SMPTE_Color_Bars_16x9.svg);background-size:cover;width:100%;height:auto;\"></canvas>"
|
||||||
|
else
|
||||||
|
echo "<p class=\"alert alert-warning\"><a href=\"majestic-settings.cgi?tab=jpeg\">Включить поддержку JPEG</a> чтобы увидеть превью.</p>"
|
||||||
|
fi
|
||||||
|
echo "<script>
|
||||||
|
function calculatePreviewSize() {
|
||||||
|
const i = new Image();
|
||||||
|
i.src = pimg;
|
||||||
|
i.onload = function() {
|
||||||
|
ratio = i.naturalWidth / i.naturalHeight;
|
||||||
|
pw = canvas.clientWidth
|
||||||
|
pw -= pw % 16
|
||||||
|
ph = pw / ratio
|
||||||
|
ph -= ph % 16
|
||||||
|
canvas.width = pw;
|
||||||
|
canvas.height = ph;
|
||||||
|
updatePreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updatePreview() {
|
||||||
|
if (typeof(pw) != 'undefined' && typeof(ph) != 'undefined') {
|
||||||
|
jpg.src = pimg + '?width=' + pw + '&height=' + ph + '&qfactor=50&t=' + Date.now();
|
||||||
|
} else {
|
||||||
|
jpg.src = pimg + '?qfactor=50&t=' + Date.now();
|
||||||
|
}
|
||||||
|
jpg.onload = function() {
|
||||||
|
ctx.drawImage(jpg, 0, 0, jpg.width, jpg.height, 0, 0, pw, ph);
|
||||||
|
canvas.style.background = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const l = document.location;
|
||||||
|
const pimg = '/cgi-bin/image.cgi';
|
||||||
|
const jpg = new Image();
|
||||||
|
jpg.addEventListener('load', async function() {
|
||||||
|
await sleep(${refresh_rate} * 1000);
|
||||||
|
updatePreview();
|
||||||
|
});
|
||||||
|
|
||||||
|
const canvas = \$('#preview');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
let pw, ph, ratio;
|
||||||
|
calculatePreviewSize();
|
||||||
|
</script>
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
progressbar() {
|
||||||
|
local c="primary"
|
||||||
|
[ "$1" -ge "75" ] && c="danger"
|
||||||
|
echo "<div class=\"progress\" role=\"progressbar\" aria-valuenow=\"${1}\" aria-valuemin=\"0\" aria-valuemax=\"100\">" \
|
||||||
|
"<div class=\"progress-bar progress-bar-striped progress-bar-animated bg-${c}\" style=\"width:${1}%\"></div>" \
|
||||||
|
"</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# redirect_back "flash class" "flash text"
|
||||||
|
redirect_back() {
|
||||||
|
redirect_to "${HTTP_REFERER:-/}" "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
# redirect_to "url" "flash class" "flash text"
|
||||||
|
redirect_to() {
|
||||||
|
[ -n "$3" ] && flash_save "$2" "$3"
|
||||||
|
echo "HTTP/1.1 303 See Other
|
||||||
|
Content-type: text/html; charset=UTF-8
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
Date: $(time_http)
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Location: $1
|
||||||
|
|
||||||
|
"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_locale() {
|
||||||
|
local -l
|
||||||
|
[ -f /etc/webui/locale ] && _l="$(cat /etc/webui/locale)"
|
||||||
|
if [ -n "$_l" ] && [ -f "/var/www/lang/${_l}.sh" ]; then
|
||||||
|
source "/var/www/lang/${_l}.sh"
|
||||||
|
locale="$_l"
|
||||||
|
else
|
||||||
|
locale="en"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
report_error() {
|
||||||
|
echo "<h4 class=\"text-danger\">Упс. Что-то произошло.</h4>"
|
||||||
|
alert "$1" "danger"
|
||||||
|
}
|
||||||
|
|
||||||
|
# report_log "text" "extras"
|
||||||
|
report_log() {
|
||||||
|
pre "$1" "small" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
report_command_error() {
|
||||||
|
echo "<h4 class=\"text-danger\">Упс. Что-то произошло.</h4>"
|
||||||
|
echo "<div class=\"alert alert-danger\">"
|
||||||
|
report_command_info "$1" "$2"
|
||||||
|
echo "</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
report_command_info() {
|
||||||
|
echo "<h4># ${1}</h4>"
|
||||||
|
echo "<pre class=\"small\">${2}</pre>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# row_ "class"
|
||||||
|
row_() {
|
||||||
|
echo "<div class\"row ${1}\" ${2}>"
|
||||||
|
}
|
||||||
|
|
||||||
|
_row() {
|
||||||
|
echo "</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
row() {
|
||||||
|
row_ "$2"
|
||||||
|
echo "$1"
|
||||||
|
_row
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize() {
|
||||||
|
local _n=$1
|
||||||
|
# strip trailing whitespace
|
||||||
|
eval $_n=$(echo \$${_n})
|
||||||
|
# escape doublequotes
|
||||||
|
eval $_n=$(echo \${$_n//\\\"/\\\\\\\"})
|
||||||
|
# escape varialbles
|
||||||
|
eval $_n=$(echo \${$_n//\$/\\\\\$})
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize4web() {
|
||||||
|
local _n=$1
|
||||||
|
# convert html entities
|
||||||
|
eval $_n=$(echo \${$_n//\\\"/\"\;})
|
||||||
|
eval $_n=$(echo \${$_n//\$/\\\$})
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_signature() {
|
||||||
|
echo "${soc} (${soc_family} family), $sensor, ${flash_size} MB ${flash_type} flash, ${fw_version}-${fw_variant}, ${network_hostname}, ${network_macaddr}" >$signature_file
|
||||||
|
}
|
||||||
|
|
||||||
|
signature() {
|
||||||
|
[ ! -f "$signature_file" ] && generate_signature
|
||||||
|
cat $signature_file
|
||||||
|
}
|
||||||
|
|
||||||
|
tab_lap() {
|
||||||
|
local _c=""
|
||||||
|
local _s="false"
|
||||||
|
[ -n "$3" ] && _s="true" && _c=" active"
|
||||||
|
echo "<li class=\"nav-item\" role=\"presentation\">" \
|
||||||
|
"<button role=\"tab\" id=\"#${1}-tab\" class=\"nav-link${_c}\"" \
|
||||||
|
" data-bs-toggle=\"tab\" data-bs-target=\"#${1}-tab-pane\"" \
|
||||||
|
" aria-controls=\"${1}-tab-pane\" aria-selected=\"${_s}\">${2}</button></li>"
|
||||||
|
}
|
||||||
|
|
||||||
|
t_checked() {
|
||||||
|
[ "$2" = "$1" ] && echo " checked"
|
||||||
|
}
|
||||||
|
|
||||||
|
t_label() {
|
||||||
|
eval "echo \$tL_${1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
t_value() {
|
||||||
|
# eval "echo \"\$${1}\""
|
||||||
|
eval echo '$'${1}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_caminfo() {
|
||||||
|
# Debug flag
|
||||||
|
debug=$(fw_printenv -n debug); [ -z "$debug" ] && debug="0"
|
||||||
|
|
||||||
|
_tmpfile=${ui_tmp_dir}/sysinfo.tmp
|
||||||
|
:>$_tmpfile
|
||||||
|
# add all web-related config files
|
||||||
|
# do not include ntp
|
||||||
|
for _f in admin email ftp motion socks5 speaker telegram webhook yadisk; do
|
||||||
|
[ -f "${ui_config_dir}/${_f}.conf" ] && cat "${ui_config_dir}/${_f}.conf" >>$_tmpfile
|
||||||
|
done; unset _f
|
||||||
|
|
||||||
|
# Hardware
|
||||||
|
flash_type=$(ipcinfo --flash-type)
|
||||||
|
|
||||||
|
flash_size=$(awk '{sum+=sprintf("0x%s", $2);} END{print sum/1048576;}' /proc/mtd)
|
||||||
|
|
||||||
|
sensor_ini=$(ipcinfo --long-sensor)
|
||||||
|
[ -z "$sensor_ini" ] && sensor_ini=$(fw_printenv -n sensor)
|
||||||
|
|
||||||
|
sensor=$(ipcinfo --short-sensor)
|
||||||
|
if [ -z "$sensor" ]; then
|
||||||
|
sensor=$(echo $sensor_ini | cut -d_ -f1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
soc=$(ipcinfo --chip-name)
|
||||||
|
if [ -z "$soc" ] || [ "unknown" = "$soc" ]; then
|
||||||
|
soc=$(fw_printenv -n soc)
|
||||||
|
fi
|
||||||
|
|
||||||
|
soc_family=$(ipcinfo --family)
|
||||||
|
if [ "unknown" = "$soc_family" ] && [ "t20" = "$soc" ]; then
|
||||||
|
soc_family="t21"
|
||||||
|
fi
|
||||||
|
|
||||||
|
soc_vendor=$(ipcinfo --vendor)
|
||||||
|
|
||||||
|
# ipcinfo reports to stderr
|
||||||
|
if [ "Temperature cannot be retrieved" = "$(ipcinfo --temp 2>&1)" ]; then
|
||||||
|
soc_has_temp="false"
|
||||||
|
else
|
||||||
|
soc_has_temp="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Firmware
|
||||||
|
fw_version=$(grep "OPENIPC_VERSION" /etc/os-release | cut -d= -f2 | tr -d /\"/)
|
||||||
|
fw_variant=$(grep "BUILD_OPTION" /etc/os-release | cut -d= -f2 | tr -d /\"/); [ -z "$fw_variant" ] && fw_variant="lite"
|
||||||
|
fw_build=$(grep "GITHUB_VERSION" /etc/os-release | cut -d= -f2 | tr -d /\"/)
|
||||||
|
mj_version=$($mj_bin_file -v)
|
||||||
|
|
||||||
|
# WebUI version
|
||||||
|
ui_version="bundled"; [ -f /var/www/.version ] && ui_version=$(cat /var/www/.version)
|
||||||
|
ui_password=$(grep root /etc/shadow|cut -d: -f2)
|
||||||
|
|
||||||
|
# Network
|
||||||
|
network_dhcp="false"
|
||||||
|
if [ -f /etc/resolv.conf ]; then
|
||||||
|
network_dns_1=$(cat /etc/resolv.conf | grep nameserver | sed -n 1p | cut -d' ' -f2)
|
||||||
|
network_dns_2=$(cat /etc/resolv.conf | grep nameserver | sed -n 2p | cut -d' ' -f2)
|
||||||
|
fi
|
||||||
|
network_hostname=$(hostname -s)
|
||||||
|
network_interfaces=$(/sbin/ifconfig | grep '^\w' | awk {'print $1'} | tr '\n' ' ' | sed 's/ $//' | sed -E 's/\blo\b\s?//')
|
||||||
|
|
||||||
|
# if no default interface then no gateway nor wan mac present
|
||||||
|
network_default_interface=$(ip r | sed -nE '/default/s/.+dev (\w+).+?/\1/p' | head -n 1)
|
||||||
|
if [ -n "$network_default_interface" ]; then
|
||||||
|
[ "$(cat /etc/network/interfaces.d/${network_default_interface} | grep inet | grep dhcp)" ] && network_dhcp="true"
|
||||||
|
network_gateway=$(ip r | sed -nE "/default/s/.+ via ([0-9\.]+).+?/\1/p")
|
||||||
|
else
|
||||||
|
network_default_interface=$(ip r | sed -nE 's/.+dev (\w+).+?/\1/p' | head -n 1)
|
||||||
|
network_gateway='' # $(fw_printenv -n gatewayip) # FIXME: Why do we need this?
|
||||||
|
# network_macaddr=$(fw_printenv -n ethaddr) # FIXME: Why do we need this?
|
||||||
|
# network_address=$(fw_printenv -n ipaddr) # FIXME: Maybe use $(hostname -i) that would return 127.0.1.1?
|
||||||
|
# network_netmask=$(fw_printenv -n netmask)
|
||||||
|
fi
|
||||||
|
network_macaddr=$(cat /sys/class/net/${network_default_interface}/address)
|
||||||
|
network_address=$(ip r | sed -nE "/${network_default_interface}/s/.+src ([0-9\.]+).+?/\1/p" | uniq)
|
||||||
|
network_cidr=$(ip r | sed -nE "/${network_default_interface}/s/^[0-9\.]+(\/[0-9]+).+?/\1/p")
|
||||||
|
network_netmask=$(ifconfig $network_default_interface | grep "Mask:" | cut -d: -f4) # FIXME: Maybe convert from $network_cidr?
|
||||||
|
|
||||||
|
overlay_root=$(mount | grep upperdir= | sed -r 's/^.*upperdir=([a-z\/]+).+$/\1/')
|
||||||
|
|
||||||
|
# Default timezone is GMT
|
||||||
|
tz_data=$(cat /etc/TZ)
|
||||||
|
tz_name=$(cat /etc/timezone)
|
||||||
|
if [ -z "$tz_data" ] || [ -z "$tz_name" ]; then
|
||||||
|
tz_data="GMT0"; echo "$tz_data" >/etc/TZ
|
||||||
|
tz_name="Etc/GMT"; echo "$tz_name" >/etc/timezone
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _vars="flash_size flash_type fw_version fw_variant fw_build
|
||||||
|
network_address network_cidr network_default_interface network_dhcp network_dns_1
|
||||||
|
network_dns_2 network_gateway network_hostname network_interfaces network_macaddr network_netmask
|
||||||
|
overlay_root mj_version soc soc_family soc_has_temp soc_vendor sensor sensor_ini tz_data tz_name
|
||||||
|
ui_password ui_version"
|
||||||
|
local v
|
||||||
|
for _v in $_vars; do
|
||||||
|
eval "echo ${_v}=\'\$${_v}\'>>${_tmpfile}"
|
||||||
|
done
|
||||||
|
# sort content alphabetically
|
||||||
|
sort <$_tmpfile | sed /^$/d >$sysinfo_file && rm $_tmpfile && unset _tmpfile
|
||||||
|
|
||||||
|
echo -e "debug=\"$debug\"\n# caminfo $(date +"%F %T")\n" >>$sysinfo_file
|
||||||
|
}
|
||||||
|
|
||||||
|
xl() {
|
||||||
|
local _c="$1"
|
||||||
|
echo "<b>${_c}</b>"
|
||||||
|
local _o=$($_c 2>&1)
|
||||||
|
[ $? -ne 0 ] && error=1
|
||||||
|
[ -n "$_o" ] && echo "<div class=\"x-small p-3\"><i>${_o}</i></div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
d() {
|
||||||
|
echo "$1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
dump() {
|
||||||
|
echo "Content-Type: text/plain; charset=UTF-8
|
||||||
|
Date: $(time_http)
|
||||||
|
Pragma: no-cache
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
$(env|sort)
|
||||||
|
--------------------
|
||||||
|
"
|
||||||
|
for x in $1; do echo -e "$x = $(eval echo \$$x)\n"; done
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
include() {
|
||||||
|
[ -f "$1" ] && source "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_tmp_dir=/tmp/webui
|
||||||
|
ui_config_dir=/etc/webui
|
||||||
|
|
||||||
|
mj_bin_file=/usr/bin/majestic
|
||||||
|
flash_file=/tmp/webui-flash.txt
|
||||||
|
signature_file=/tmp/webui/signature.txt
|
||||||
|
sysinfo_file=/tmp/sysinfo.txt
|
||||||
|
|
||||||
|
[ ! -d $ui_tmp_dir ] && mkdir -p $ui_tmp_dir
|
||||||
|
[ ! -d $ui_config_dir ] && mkdir -p $ui_config_dir
|
||||||
|
|
||||||
|
lang_path=/var/www/lang/
|
||||||
|
[ ! -d $lang_path ] && mkdir -p $lang_path
|
||||||
|
|
||||||
|
[ ! -f $sysinfo_file ] && update_caminfo
|
||||||
|
include $sysinfo_file
|
||||||
|
|
||||||
|
pagename=$(basename "$SCRIPT_NAME")
|
||||||
|
pagename="${pagename%%.*}"
|
||||||
|
|
||||||
|
include p/locale_en.sh
|
||||||
|
include p/mj.cgi
|
||||||
|
include /etc/webui/mqtt.conf
|
||||||
|
include /etc/webui/socks5.conf
|
||||||
|
include /etc/webui/speaker.conf
|
||||||
|
include /etc/webui/telegram.conf
|
||||||
|
include /etc/webui/webhook.conf
|
||||||
|
include /etc/webui/webui.conf
|
||||||
|
include /etc/webui/yadisk.conf
|
||||||
|
|
||||||
|
# reload_locale
|
||||||
|
|
||||||
|
# FIXME: mandatory password change disabled for testing purposes
|
||||||
|
check_password
|
||||||
|
get_soc_temp
|
||||||
|
%>
|
|
@ -0,0 +1,40 @@
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="x-small">
|
||||||
|
<div class="container pt-3">
|
||||||
|
<p class="text-end">Работает на <a href="https://github.com/OpenIPC/microbe-web">Microbe Web UI</a>, части <a href="https://openipc.org/">OpenIPC </a>, доработано <a href="https://meldana.com/services/remont-i-razrabotka/razrabotka-elektroniki/">Meldana RND</a>.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<% if [ "$debug" -ge "1" ]; then %>
|
||||||
|
<button id="debug-button" type="button" class="btn btn-primary btn-sm m-2 float-start"
|
||||||
|
data-bs-toggle="offcanvas" data-bs-target="#offcanvasDebug"
|
||||||
|
aria-controls="offcanvasDebug">Debug</button>
|
||||||
|
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasDebug" aria-labelledby="offcanvasDebugLabel">
|
||||||
|
<div class="offcanvas-header">
|
||||||
|
<h5 class="offcanvas-title" id="offcanvasDebugLabel">Debug Info</h5>
|
||||||
|
<form action="webui.cgi" method="post">
|
||||||
|
<% field_hidden "action" "init" %>
|
||||||
|
<% button_submit "Обновить оболочку" %>
|
||||||
|
</form>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Закрыть"></button>
|
||||||
|
</div>
|
||||||
|
<div class="offcanvas-body x-small">
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<% tab_lap "t1" "sysinfo" "active" %>
|
||||||
|
<% tab_lap "t2" "env" %>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content p-2" id="tab-content">
|
||||||
|
<div id="t1-tab-pane" role="tabpanel" class="tab-pane fade active show" aria-labelledby="t1-tab" tabindex="0">
|
||||||
|
<% ex "cat /tmp/sysinfo.txt" %>
|
||||||
|
</div>
|
||||||
|
<div id="t2-tab-pane" role="tabpanel" class="tab-pane fade" aria-labelledby="t2-tab" tabindex="0">
|
||||||
|
<% ex "env | sort" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,176 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
Content-type: text/html; charset=UTF-8
|
||||||
|
Date: <%= $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') %>
|
||||||
|
Server: <%= $SERVER_SOFTWARE %>
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<%= ${locale:=en} %>" data-bs-theme="<%= ${webui_theme:=light} %>">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title><% html_title %></title>
|
||||||
|
<link rel="stylesheet" href="/a/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/a/bootstrap.override.css">
|
||||||
|
<script src="/a/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="/a/main.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="page-<%= $pagename %>" class="<%= $fw_variant %> <%= ${webui_level:-user} %><% [ "$debug" -ge "1" ] && echo -n " debug" %>">
|
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="status.cgi"><img alt="Image: OpenIPC logo" height="64" src="/a/logo.svg"></a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="preview.cgi">Предпросмотр</a></li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownSettings" role="button">Система</a>
|
||||||
|
<ul aria-labelledby="dropdownInformation" class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="status.cgi">Обзор</a></li>
|
||||||
|
<li><a class="dropdown-item" href="firmware.cgi">Прошивка</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownSettings" role="button">Настройки</a>
|
||||||
|
<ul aria-labelledby="dropdownSettings" class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="network.cgi">Сеть</a></li>
|
||||||
|
<li><a class="dropdown-item" href="time-config.cgi">Время</a></li>
|
||||||
|
<li><a class="dropdown-item" href="network-socks5.cgi">SOCKS5 Proxy</a></li>
|
||||||
|
<li><a class="dropdown-item" href="webui-settings.cgi">Настройки Веб-Интерфейса</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="reset.cgi">Перезагрузка...</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownMajestic" role="button">Маджестик</a>
|
||||||
|
<ul aria-labelledby="dropdownMajestic" class="dropdown-menu">
|
||||||
|
<%
|
||||||
|
mj=$(echo "$mj" | sed "s/ /_/g")
|
||||||
|
for _line in $mj; do
|
||||||
|
_parameter=${_line%%|*};
|
||||||
|
_param_name=${_parameter#.};
|
||||||
|
_param_domain=${_param_name%.*}
|
||||||
|
if [ "$_parameter_domain_old" != "$_param_domain" ]; then
|
||||||
|
# hide certain domains if not supported
|
||||||
|
[ -n "$(eval echo "\$mj_hide_${_param_domain}" | sed -n "/\b${soc_family}\b/p")" ] && continue
|
||||||
|
[ -n "$(eval echo "\$mj_show_${_param_domain}_vendor")" ] && [ -z "$(eval echo "\$mj_show_${_param_domain}_vendor" | sed -n "/\b${soc_vendor}\b/p")" ] && continue
|
||||||
|
_parameter_domain_old="$_param_domain"
|
||||||
|
_css="class=\"dropdown-item\""; [ "$_param_domain" = "$only" ] && _css="class=\"dropdown-item active\" aria-current=\"true\""
|
||||||
|
echo "<li><a ${_css} href=\"majestic-settings.cgi?tab=${_param_domain}\">$(eval echo \$tT_mj_${_param_domain})</a></li>"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset _css; unset _param_domain; unset _line; unset _param_name; unset _parameter_domain_old; unset _parameter;
|
||||||
|
%>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="majestic-endpoints.cgi">Majestic Endpoints</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownTools" role="button">Инструменты</a>
|
||||||
|
<ul aria-labelledby="dropdownTools" class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="tools.cgi">Пинг и трассировка</a></li>
|
||||||
|
<li><a class="dropdown-item" href="sdcard.cgi">Карта памяти</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownServices" role="button">Сервисы</a>
|
||||||
|
<ul aria-labelledby="dropdownServices" class="dropdown-menu">
|
||||||
|
<% load_plugins %>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownHelp" role="button">Помощь</a>
|
||||||
|
<ul aria-labelledby="dropdownHelp" class="dropdown-menu dropdown-menu-lg-end">
|
||||||
|
<li><a class="dropdown-item" href="https://openipc.org/">Об IpenIPC</a></li>
|
||||||
|
<li><a class="dropdown-item" href="https://meldana.com/">Мелдана</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="pb-4">
|
||||||
|
<div class="container" style="min-height: 90vh">
|
||||||
|
<div class="row mt-1 x-small">
|
||||||
|
<div class="col-lg-2">
|
||||||
|
<div id="pb-memory" class="progress my-1" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar"></div></div>
|
||||||
|
<div id="pb-overlay" class="progress my-1" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar"></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-7 mb-2">
|
||||||
|
<%= $(signature) %>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-lg-3 mb-2 text-end">
|
||||||
|
<div id="time-now"></div>
|
||||||
|
<div id="soc-temp"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% if [ -z "$network_gateway" ]; then %>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<p class="mb-0">Нет соединения с интернетом. Пожалуйста <a href="network.cgi">проверьте Ваши сетевые настройки</a>.</p>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ "$network_macaddr" = "00:00:23:34:45:66" ]; then %>
|
||||||
|
<%in p/mac-address.cgi %>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ "true" = "$openwall_socks5_enabled" ] || [ "true" = "$telegram_socks5_enabled" ] || [ "true" = "$yadisk_socks5_enabled" ]; then
|
||||||
|
if [ -z "$socks5_host" ] || [ -z "$socks5_port" ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-0">Вы хотите использовать прокси SOCKS5, но он не настроен! Пожалуйста <a href="network-socks5.cgi">настройте Proxy</a>.</p>
|
||||||
|
</div>
|
||||||
|
<% fi; fi %>
|
||||||
|
|
||||||
|
<% if [ "true" = "$speaker_enabled" ] && [ "true" != "$(yaml-cli -g .audio.enabled)" ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-0">Вам нужно включить звук в <a href="majestic-settings.cgi?tab=audio">Majestic settings.</a></p>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ "$(cat /etc/TZ)" != "$TZ" ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>$TZ переменная в системной среде нуждается в обновлении!</p>
|
||||||
|
<span class="d-flex gap-3">
|
||||||
|
<a class="btn btn-danger" href="reboot.cgi">Перезагрузить камеру</a>
|
||||||
|
<a class="btn btn-primary" href="timezone.cgi">Просмотр настроек часового пояса</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ -f /tmp/network-restart.txt ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>Настройки сети обновлены. Перезапустите камеру, чтобы применить изменения.</p>
|
||||||
|
<span class="d-flex gap-3">
|
||||||
|
<a class="btn btn-danger" href="reboot.cgi">Перезагрузить камеру</a>
|
||||||
|
<a class="btn btn-primary" href="network.cgi">Просмотр сетевых настроек</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ -f /tmp/coredump-restart.txt ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>Обновлены настройки отладки Majestic. Перезапустите, чтобы применить изменения.</p>
|
||||||
|
<span class="d-flex gap-3">
|
||||||
|
<a class="btn btn-danger" href="reboot.cgi">Перезагрузить камеру</a>
|
||||||
|
<a class="btn btn-primary" href="debugging.cgi">Просмотр настроек отладки</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<% if [ -f /tmp/motionguard-restart.txt ]; then %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>Обнаружены изменения в конфигурации защиты от движения. Пожалуйста, перезапустите камеру, чтобы изменения вступили в силу.</p>
|
||||||
|
<span class="d-flex gap-3">
|
||||||
|
<a class="btn btn-danger" href="reboot.cgi">Перезагрузить камеру</a>
|
||||||
|
<a class="btn btn-primary" href="plugin-motion.cgi">Просмотр настроек защиты от движения</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<h2><%= $page_title %></h2>
|
||||||
|
<% flash_read %>
|
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#name:English
|
||||||
|
|
||||||
|
tT_mj_audio="Audio"
|
||||||
|
tT_mj_cloud="Cloud Support"
|
||||||
|
tT_mj_hls="HTTP Live Streaming (HLS)"
|
||||||
|
tT_mj_image="Image"
|
||||||
|
tT_mj_ipeye="IPEYE Protocol"
|
||||||
|
tT_mj_isp="Image Signal Processor (ISP)"
|
||||||
|
tT_mj_jpeg="JPEG"
|
||||||
|
tT_mj_mjpeg="MJPEG"
|
||||||
|
tT_mj_motionDetect="In-Camera Motion Detection"
|
||||||
|
tT_mj_netip="NETIP Protocol"
|
||||||
|
tT_mj_nightMode="Night Mode"
|
||||||
|
tT_mj_onvif="ONVIF Protocol"
|
||||||
|
tT_mj_osd="On-screen Display (OSD)"
|
||||||
|
tT_mj_records="Recording"
|
||||||
|
tT_mj_rtsp="Real Time Streaming Protocol (RTSP)"
|
||||||
|
tT_mj_system="System"
|
||||||
|
tT_mj_video0="Mainstream Video (Video0)"
|
||||||
|
tT_mj_video1="Substream Video (Video1)"
|
||||||
|
tT_mj_watchdog="Watchdog"
|
||||||
|
tT_mj_youtube="Youtube"
|
||||||
|
t_nav_mj_audio="Audio"
|
||||||
|
t_nav_mj_cloud="Cloud"
|
||||||
|
t_nav_mj_hls="HLS"
|
||||||
|
t_nav_mj_image="Image"
|
||||||
|
t_nav_mj_isp="ISP"
|
||||||
|
t_nav_mj_jpeg="JPEG"
|
||||||
|
t_nav_mj_mjpeg="MJPEG"
|
||||||
|
t_nav_mj_motionDetect="Motion"
|
||||||
|
t_nav_mj_netip="NETIP"
|
||||||
|
t_nav_mj_nightMode="Night Mode"
|
||||||
|
t_nav_mj_onvif="ONVIF"
|
||||||
|
t_nav_mj_osd="OSD"
|
||||||
|
t_nav_mj_records="Recording"
|
||||||
|
t_nav_mj_rtsp="RTSP"
|
||||||
|
t_nav_mj_system="System"
|
||||||
|
t_nav_mj_video0="Video0"
|
||||||
|
t_nav_mj_video1="Video1"
|
||||||
|
t_nav_mj_watchdog="Watchdog"
|
||||||
|
t_nav_mj_youtube="Youtube"
|
|
@ -0,0 +1,37 @@
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h3>Эта камера использует MAC-адрес <b>00:00:23:34:45:66</b> который является заполнителем.</h3>
|
||||||
|
<p>Вам необходимо заменить его оригинальным MAC-адресом из резервной копии стоковой прошивки или <a href="#" id="generate-mac-address">сгенерировать случайный действительный MAC-адрес</a>.</p>
|
||||||
|
<form action="network.cgi" method="POST" class="row gy-2 gx-3 align-items-center mb-3">
|
||||||
|
<input type="hidden" name="action" value="changemac">
|
||||||
|
<div class="col-auto"><label class="form-label" for="mac_address">Новый MAC-адрес</label></div>
|
||||||
|
<div class="col-auto"><input class="form-control" id="mac_address" name="mac_address"type="text"></div>
|
||||||
|
<div class="col-auto"><input class="btn btn-danger" type="submit" value="Сменить MAC-адрес"></div>
|
||||||
|
</form>
|
||||||
|
<p class="mb-0">Обратите внимание, что новый MAC-адрес, скорее всего, даст камере новый IP-адрес, назначенный DHCP-сервером!</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function generateMacAddress(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const el = document.querySelector('#mac_address');
|
||||||
|
if (el.value == "") {
|
||||||
|
let mac = "";
|
||||||
|
for (let i = 1; i <= 6; i++) {
|
||||||
|
let b = ((Math.random() * 255) >>> 0);
|
||||||
|
if (i === 1) {
|
||||||
|
b = b | 2;
|
||||||
|
b = b & ~1;
|
||||||
|
}
|
||||||
|
mac += b.toString(16).toUpperCase().padStart(2, '0');
|
||||||
|
if (i < 6) mac += ":";
|
||||||
|
}
|
||||||
|
el.value = mac;
|
||||||
|
} else {
|
||||||
|
alert("В поле MAC-адреса есть значение. Пожалуйста, очистите поле и повторите попытку.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
document.querySelector('#generate-mac-address').addEventListener('click', generateMacAddress);
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,98 @@
|
||||||
|
# line format: parameter|label|units|type|o,p,t,i,o,n,s|placeholder|hint
|
||||||
|
# line format: parameter|type
|
||||||
|
mj_retired="
|
||||||
|
.system.sensorConfigDir|Путь к каталогу конфигурации датчиков||string||/etc/sensors|
|
||||||
|
.system.updateChannel|Канал для обновлений||select|testing,beta,stable,none|stable|
|
||||||
|
.isp.alignWidth|Выровнять ширину||number||8|
|
||||||
|
.isp.threadStackSize|Размер стека потоков|KB|number|1-32|16|
|
||||||
|
.motionDetect.profile|Профиль обнаружения движения||select|outdoor,indoor|indoor|i||
|
||||||
|
.raw.enabled|Включить поддержку необработанных фидов||boolean|true,false|false|
|
||||||
|
.raw.mode|Режим сырой подачи||select|slow,fast,none|slow|
|
||||||
|
"
|
||||||
|
|
||||||
|
# line format: parameter|label|units|type|o,p,t,i,o,n,s|placeholder|hint
|
||||||
|
# number options: min,max,step
|
||||||
|
# range options: min,max,step[,button]
|
||||||
|
# select options: value2,value2,value3...
|
||||||
|
mj="
|
||||||
|
.image.mirror|Перевернуть изображение по горизонтали||boolean|true,false|false|
|
||||||
|
.image.flip|Отразить изображение по вертикали||boolean|true,false|false|
|
||||||
|
.image.rotate|Повернуть изображение по часовой стрелке, °||select|0,90,270|0|
|
||||||
|
.image.contrast|Контраст изображения|%|range|1,100,1,auto|auto|
|
||||||
|
.image.hue|Оттенок изображения|%|range|1,100,1|50|
|
||||||
|
.image.saturation|Насыщенность изображения|%|range|1,100,1|50|
|
||||||
|
.image.luminance|Яркость изображения|%|range|1,100,1,auto|auto|
|
||||||
|
.osd.enabled|Включить экранное меню (OSD)||boolean|true,false|false|
|
||||||
|
.osd.font|Путь к файлу шрифта, используемому в экранного меню||string||/usr/share/fonts/truetype/UbuntuMono-Regular.ttf|
|
||||||
|
.osd.template|Шаблон экранного меню||string||%a %e %B %Y %H:%M:%S %Z|Поддержка формата <a href=\"https://man7.org/linux/man-pages/man3/strftime.3.html \" target=\"_blank\">strftime()</a>.
|
||||||
|
.osd.corner|Предустановленное положение экранного меню||select|tl:Сверху слева,tr:Сверху справа,bl:Снизу слева,br:Снизу справа|br|
|
||||||
|
.osd.posX|Горизонтальное положение экранного меню|px|number|-2000,2000,2|-100|
|
||||||
|
.osd.posY|Вертикальное положение экранного меню|px|number|-2000,2000,2|-100|
|
||||||
|
.osd.privacyMasks|Маски конфиденциальности|px|string||0x0x234x640,2124x0x468x1300|Координаты маскируемых областей через запятую.
|
||||||
|
.nightMode.enabled|Включить ночной режим||boolean|true,false|false|
|
||||||
|
.records.enabled|Включить сохранение записей||boolean|true,false|false|
|
||||||
|
.records.path|Шаблон для сохранения видеозаписей||string||/mnt/mmc/%Y/%m/%d/%H.mp4|Поддержка формата <a href=\"https://man7.org/linux/man-pages/man3/strftime.3.html \" target=\"_blank\">strftime()</a>.
|
||||||
|
.records.maxUsage|Ограничение использования доступного пространства|%|range|1,100,1|95|
|
||||||
|
.records.timelapseInterval|Интервал захвата ускоренной съемки|sec|number|1,65355,1|5|В секундах
|
||||||
|
.records.timelapseFrameRate|Частота кадров выходного файла ускоренной съемки|fps|number|1,100,1|2|В кадрах в секунду
|
||||||
|
.video0.enabled|Включить основной видеопоток||boolean|true,false|true|
|
||||||
|
.video0.codec|Кодек основного видеопотока||select|h264,h265|h264|
|
||||||
|
.video0.size|разрешение видео|px|string|1920x1080,1280x720,704x576|1920x1080|
|
||||||
|
.video0.fps|Частота кадров видео|fps|number|1,60,1|25|
|
||||||
|
.video0.bitrate|Битрейт видео|kbps|number|1,68000,1|4096|
|
||||||
|
.video0.gopSize|Отправка I-кадров каждую секунду||number|0.1,20,0.1|1|
|
||||||
|
.video0.gopMode|Режим групповых снимков (GOP)||select|normal,dual,smart|normal|
|
||||||
|
.video0.rcMode|режим дистанционного управления||select|avbr,cbr,vbr|avbr|
|
||||||
|
.video0.crop|Обрезать видео по размеру|px|string||0x0x960x540|
|
||||||
|
.video0.sliceUnits|Количество фрагментов на кадр||number|1,10,1|4
|
||||||
|
.video1.enabled|Включить дополнительный видеопоток||boolean|true,false|false|
|
||||||
|
.video1.codec|Кодек дополнительного видеопотока||select|h264,h265|h264|
|
||||||
|
.video1.size|Разрешение видео|px|string|1920x1080,1280x720,704x576|704x576|
|
||||||
|
.video1.fps|Частота кадров видео|fps|number|1,60,1|15|
|
||||||
|
.video1.bitrate|Битрейт видео|kbps|number|1,68000,1|2048|
|
||||||
|
.video1.gopSize|Отправка I-кадров каждую секунду||number|1,20,1|1|
|
||||||
|
.video1.gopMode|Режим групповых снимков (GOP)||select|normal,dual,smart|normal|
|
||||||
|
.video1.rcMode|режим дистанционного управления||select|avbr|avbr|
|
||||||
|
.video1.crop|Обрезать видео по размеру|px|string||0x0x960x540|
|
||||||
|
.video1.sliceUnits|Количество фрагментов на кадр||number|1,10,1|4
|
||||||
|
.jpeg.enabled|Включить поддержку JPEG||boolean|true,false|true|
|
||||||
|
.jpeg.size|Размер снимка|px|string||1920x1080|
|
||||||
|
.jpeg.qfactor|Уровень качества JPEG|%|range|1,100,1|50|
|
||||||
|
.jpeg.toProgressive|Progressive JPEG||boolean|true,false|false|
|
||||||
|
.audio.enabled|Включить звук||boolean|true,false|false|
|
||||||
|
.audio.volume|Уровень громкости звука|%|range|1,100,1,auto|auto|
|
||||||
|
.audio.srate|Частота дискретизации звука|kHz|number|1,96000,1|8000|
|
||||||
|
.audio.codec|Кодек для кодирования RTSP и MP4||select|mp3,opus,aac,pcm,alaw,ulaw|opus|
|
||||||
|
.audio.device|Аудио карта||string||hw:2|
|
||||||
|
.audio.outputEnabled|Включить аудиовыход||boolean|true,false|false|
|
||||||
|
.audio.outputGain|Выходное усиление||range|0,31,1|15|
|
||||||
|
.audio.outputVolume|Громкость динамика|%|range|0,100,1|0|
|
||||||
|
.audio.voiceEqualizer|Аудио эквалайзер||select|disabled,common,music,noisy|disabled|
|
||||||
|
.audio.speakerPin|Контакт GPIO аудиодинамика||number|1,255,1|32|
|
||||||
|
.audio.speakerPinInvert|Сигнал динамика инвертирован||boolean|true,false|false|
|
||||||
|
.rtsp.enabled|Включить вывод||boolean|true,false|true|
|
||||||
|
.rtsp.port|Порт для протокола RTSP||number|1,65535,1|554|rtsp://user:pass@${network_address}:[port]/stream={0,1}
|
||||||
|
.hls.enabled|Включить прямую трансляцию HTTP(HLS)||boolean|true,false|true|
|
||||||
|
.youtube.enabled|Включить поддержку Youtube||boolean|true,false|false|
|
||||||
|
.youtube.key|API-ключ Youtube||string||xxxx-xxxx-xxxx-xxxx-xxxx|
|
||||||
|
.motionDetect.enabled|Включить обнаружение движения||boolean|true,false|false|
|
||||||
|
.motionDetect.visualize|Визуализация обнаружения движения||boolean|true,false|true|
|
||||||
|
.motionDetect.debug|Включить отладку||boolean|true,false|true|
|
||||||
|
.motionDetect.roi|Области интереса (ROI) для обнаружения движения.|px|string||0x0x1296x760|
|
||||||
|
.motionDetect.skipIn|Регионы, исключенные из ROI.|px|string||20x20x200x300,510x330x40x15|
|
||||||
|
.ipeye.enabled|Включить поддержку IPEYE||boolean|true,false|false|
|
||||||
|
.onvif.enabled|Включить поддержку протокола ONVIF||boolean|true,false|false|
|
||||||
|
.cloud.enabled|Enable cloud supportВключить облачную поддержку||boolean|true,false|false|
|
||||||
|
"
|
||||||
|
|
||||||
|
# hide these settings unless in debug mode
|
||||||
|
mj_hide_unless_debug="audio_device isp_aGain isp_dGain isp_ispGain isp_exposure"
|
||||||
|
|
||||||
|
# conditional settings limiters
|
||||||
|
mj_show_audio_voiceEqualizer="gk7205v200 hi3516cv300 hi3516cv500 hi3516ev300 hi3519v101"
|
||||||
|
mj_show_mjpeg_vendor="goke hisilicon"
|
||||||
|
mj_show_isp_slowShutter_vendor="goke hisilicon"
|
||||||
|
mj_hide_isp_sensorConfig_vendor="ingenic"
|
||||||
|
mj_hide_video0_codec="hi3516cv200 hi3516cv100"
|
||||||
|
mj_hide_video1_codec="hi3516cv200 hi3516cv100"
|
||||||
|
mj_hide_motionDetect="hi3516cv100 hi3516av100"
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>Сброс прошивки</h4>
|
||||||
|
<p>Верните прошивку в исходное состояние, удалив раздел оверлея. Все пользовательские настройки и все файлы, хранящиеся в оверлейном разделе, будут потеряны.!</p>
|
||||||
|
<% button_reset_firmware %>
|
||||||
|
</div>
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="motion"
|
||||||
|
plugin_name="Детекция движения"
|
||||||
|
page_title="Детекция движения"
|
||||||
|
params="enabled sensitivity send2telegram send2yadisk playonspeaker throttle"
|
||||||
|
|
||||||
|
[ -n "$(echo "$mj_hide_motionDetect" | sed -n "/\b${soc_family}\b/p")" ] &&
|
||||||
|
redirect_to "/" "danger" "Обнаружение движения не поддерживается вашей камерой."
|
||||||
|
|
||||||
|
service_file=/etc/init.d/S92motion
|
||||||
|
tmp_file=/tmp/${plugin}
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$motion_enabled" ]; then
|
||||||
|
[ "false" = "$motion_send2telegram" ] && \
|
||||||
|
[ "false" = "$motion_send2yadisk" ] && \
|
||||||
|
[ "false" = "$motion_playonspeaker" ] && \
|
||||||
|
flash_append "danger" "Вам нужно выбрать хотя бы один способ уведомления" && error=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
if [ "true" = "$motion_enabled" ]; then
|
||||||
|
if [ -z "$(eval echo "DEBUG TRACE" | sed -n "/\b$(yaml-cli -g .system.logLevel)\b/p")" ]; then
|
||||||
|
# make required changes to majestic.yaml
|
||||||
|
_t=$(mktemp)
|
||||||
|
cp -f /tmp/majestic.yaml $_t
|
||||||
|
yaml-cli -i $_t -s .system.logLevel DEBUG
|
||||||
|
yaml-cli -i $_t -s .motionDetect.visualize true
|
||||||
|
yaml-cli -i $_t -s .motionDetect.debug true
|
||||||
|
mv -f $_t /tmp/majestic.yaml
|
||||||
|
unset _t
|
||||||
|
fi
|
||||||
|
# touch /tmp/motionguard-restart.txt
|
||||||
|
/etc/init.d/S92motion restart >/dev/null
|
||||||
|
else
|
||||||
|
/etc/init.d/S92motion stop >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_to "$SCRIPT_NAME"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
include $config_file
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
[ -z "$motion_sensitivity" ] && motion_sensitivity=45
|
||||||
|
[ -z "$motion_throttle" ] && motion_throttle=10
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col col-lg-4">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_switch "motion_enabled" "Включить детекцию движения" %>
|
||||||
|
<% field_range "motion_sensitivity" "Чувствительность" "1,50,1" "1 - минимальная чувствительность, 50 - максимальная чувствительность" %>
|
||||||
|
<% field_range "motion_throttle" "Задержка между уведомлениями, сек." "1,30,1" %>
|
||||||
|
<h5>Действия</h5>
|
||||||
|
<ul class="list-group mb-3">
|
||||||
|
<li class="list-group-item send2telegram">
|
||||||
|
<% field_checkbox "motion_send2telegram" "Отправить в Телеграм" "<a href=\"plugin-send2telegram.cgi\">Настроить отправку в Telegram</a>" %>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item send2yadisk">
|
||||||
|
<% field_checkbox "motion_send2yadisk" "Отправить на яндекс диск" "<a href=\"plugin-send2yadisk.cgi\">Настроить отправку на Яндекс Диск</a>" %>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item playonspeaker">
|
||||||
|
<% field_checkbox "motion_playonspeaker" "Воспроизвести звуковой файл на динамике" "<a href=\"plugin-playonspeaker.cgi\">Настроить воспроизведение на динамике</a>" %>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
<% [ "true" != "$telegram_enabled" ] && echo "\$('#motion_send2telegram').disabled = true;" %>
|
||||||
|
<% [ "true" != "$yadisk_enabled" ] && echo "\$('#motion_send2yadisk').disabled = true;" %>
|
||||||
|
<% [ "true" != "$speaker_enabled" ] && echo "\$('#motion_playonspeaker').disabled = true;" %>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="speaker"
|
||||||
|
plugin_name="Проиграть на динамике"
|
||||||
|
page_title="Проиграть на динамик"
|
||||||
|
params="enabled url file"
|
||||||
|
# volume srate codec outputEnabled speakerPin speakerPinInvert
|
||||||
|
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$speaker_enabled" ]; then
|
||||||
|
[ -z "$speaker_url" ] && flash_append "danger" "URL-адрес не может быть пустым." && error=11
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "конфигурация ${plugin_name} обновлена."
|
||||||
|
fi
|
||||||
|
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
else
|
||||||
|
include $config_file
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
[ -z "$speaker_url" ] && speaker_url="http://127.0.0.1/play_audio"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_switch "speaker_enabled" "Включить воспроизведение на динамике" %>
|
||||||
|
<% field_text "speaker_url" "URL" %>
|
||||||
|
<% field_text "speaker_file" "Аудио файл" "<a href=\"https://github.com/OpenIPC/wiki/blob/master/en/majestic-streamer.md#how-to-create-an-audio-file-to-play-on-cameras-speaker-over-network\">a-law PCM 8000 Бит/сек</a>" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<% ex "cat $config_file" %>
|
||||||
|
<% button_webui_log %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="telegram"
|
||||||
|
plugin_name="Отправить в Телеграм"
|
||||||
|
page_title="Отправить в Телеграмm"
|
||||||
|
params="enabled token as_attachment as_photo channel caption socks5_enabled"
|
||||||
|
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$telegram_enabled" ]; then
|
||||||
|
[ -z "$telegram_token" ] && flash_append "danger" "Токен Telegram не может быть пустым." && error=11
|
||||||
|
[ -z "$telegram_channel" ] && flash_append "danger" "Канал Telegram не может быть пустым." && error=12
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "Конфигурация ${plugin_name} обновлена."
|
||||||
|
fi
|
||||||
|
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
else
|
||||||
|
include $config_file
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
[ -z "$telegram_caption" ] && telegram_caption="%hostname, %datetime"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_switch "telegram_enabled" "Включить отправку в Telegram" %>
|
||||||
|
<% field_text "telegram_token" "Token" "Ваш токен аутентификации Telegram Bot." %>
|
||||||
|
<% field_text "telegram_channel" "Chat ID" "Числовой идентификатор канала, на который бот должен публиковать изображения.." %>
|
||||||
|
<% field_switch "telegram_as_photo" "Отправить как фото." %>
|
||||||
|
<% field_text "telegram_caption" "Подпись к фотографии" "Доступные переменные: %hostname, %datetime, %soctemp." %>
|
||||||
|
<% field_switch "telegram_as_attachment" "Отправить как вложение." %>
|
||||||
|
<% field_switch "telegram_socks5_enabled" "Использовать SOCKS5." "<a href=\"network-socks5.cgi\">Конфигурация</a> доступа SOCKS5" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if [ -z "$telegram_token" ]; then %>
|
||||||
|
<div class="alert alert-info mt-4">
|
||||||
|
<h5>Чтобы создать канал для вашего бота Telegram:</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Начните чат сh <a href=\"https://t.me/BotFather\">@BotFather</a></li>
|
||||||
|
<li>Введите <code>/start</code> чтобы начать сеанс.</li>
|
||||||
|
<li>Введите <code>/newbot</code> создать нового бота.</li>
|
||||||
|
<li>Дайте вашему каналу бота имя, например: <i>cool_cam_bot</i>.</li>
|
||||||
|
<li>Дайте вашему боту имя пользователя, например: <i>CoolCamBot</i>.</li>
|
||||||
|
<li>Скопируйте токен, назначенный BotFather вашему новому боту, и вставьте его в форму.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="yadisk"
|
||||||
|
plugin_name="Отправить на Яндекс.Диск"
|
||||||
|
page_title="Отправить на Яндекс.Диск"
|
||||||
|
params="enabled username password path socks5_enabled"
|
||||||
|
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$email_enabled" ]; then
|
||||||
|
[ -z "$yadisk_username" ] && flash_append "danger" "Имя пользователя Яндекс.Диска не может быть пустым." && error=11
|
||||||
|
[ -z "$yadisk_password" ] && flash_append "danger" "Пароль Яндекс.Диска не может быть пустым." && error=12
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "Конфигарция ${plugin_name} обновлена."
|
||||||
|
fi
|
||||||
|
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
else
|
||||||
|
include $config_file
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_switch "yadisk_enabled" "Включить бота Яндекс.Диска" %>
|
||||||
|
<% field_text "yadisk_username" "Имя пользователя Яндекс.Диска" %>
|
||||||
|
<% field_password "yadisk_password" "Пароль от Яндекс.Диска" "Специальный пароль для приложения. <a href=\"https://yandex.com/support/id/authorization/app-passwords.html\">Создайте его здесь</a>." %>
|
||||||
|
<% field_text "yadisk_path" "Путь к Яндекс.Диску" %>
|
||||||
|
<% field_switch "yadisk_socks5_enabled" "Использовать SOCKS5" "<a href=\"network-socks5.cgi\">Конфигурация</a> доступа SOCKS5" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,147 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="telegrambot"
|
||||||
|
plugin_name="Телеграм Бот"
|
||||||
|
page_title="Телеграм Бот"
|
||||||
|
|
||||||
|
params="enabled token"
|
||||||
|
for i in 0 1 2 3 4 5 6 7 8 9; do
|
||||||
|
params="${params} command_${i} description_${i} script_${i}"
|
||||||
|
done
|
||||||
|
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$telegrambot_enabled" ]; then
|
||||||
|
[ -z "$telegrambot_token" ] &&
|
||||||
|
flash_append "danger" "Токен Telegram не может быть пустым." &&
|
||||||
|
error=11
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
|
||||||
|
/etc/init.d/S93telegrambot restart >/dev/null
|
||||||
|
|
||||||
|
redirect_back "success" "Конфигурация ${plugin_name} обновлена."
|
||||||
|
fi
|
||||||
|
|
||||||
|
redirect_to $SCRIPT_NAME
|
||||||
|
else
|
||||||
|
include $config_file
|
||||||
|
|
||||||
|
for _p in $params; do
|
||||||
|
sanitize4web "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
[ -z "$telegrambot_caption" ] && telegrambot_caption="%hostname, %datetime"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-1 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_switch "telegrambot_enabled" "Включить Telegram-бота" %>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="text" id="telegrambot_token" name="telegrambot_token" value="<%= $telegrambot_token %>"
|
||||||
|
class="form-control" placeholder="Токен бота" aria-label="Ваш токен аутентификации Telegram Bot.">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<button type="button" class="btn" data-bs-toggle="modal" data-bs-target="#helpModal">Помощь</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bot-commands mb-4">
|
||||||
|
<h5>Команды бота</h5>
|
||||||
|
<p class="hint mb-3">Use $chat_id переменная для идентификатора активного чата.</p>
|
||||||
|
<% for i in 0 1 2 3 4 5 6 7 8 9; do %>
|
||||||
|
<div class="row g-1 mb-3 mb-lg-1">
|
||||||
|
<div class="col-4 col-lg-2">
|
||||||
|
<input type="text" id="telegrambot_command_<%= $i %>" name="telegrambot_command_<%= $i %>"
|
||||||
|
class="form-control" placeholder="Команда бота" value="<%= $(t_value "telegrambot_command_$i") %>">
|
||||||
|
</div>
|
||||||
|
<div class="col-8 col-lg-3">
|
||||||
|
<input type="text" id="telegrambot_description_<%= $i %>" name="telegrambot_description_<%= $i %>"
|
||||||
|
class="form-control" placeholder="Описание команды" value="<%= $(t_value "telegrambot_description_$i") %>">
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-7">
|
||||||
|
<input type="text" id="telegrambot_script_<%= $i %>" name="telegrambot_script_<%= $i %>"
|
||||||
|
class="form-control" placeholder="Команда Линкус" value="<%= $(t_value "telegrambot_script_$i") %>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% done %>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-danger float-end" id="reset_commands">Сбросить команды</button>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="helpModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">To create a Telegram bot</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<h5>Чтобы создать канал для вашего бота Telegram:</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Начните чат сh <a href=\"https://t.me/BotFather\">@BotFather</a></li>
|
||||||
|
<li>Введите <code>/start</code> чтобы начать сеанс.</li>
|
||||||
|
<li>Введите <code>/newbot</code> создать нового бота.</li>
|
||||||
|
<li>Дайте вашему каналу бота имя, например: <i>cool_cam_bot</i>.</li>
|
||||||
|
<li>Дайте вашему боту имя пользователя, например: <i>CoolCamBot</i>.</li>
|
||||||
|
<li>Скопируйте токен, назначенный BotFather вашему новому боту, и вставьте его в форму.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const default_commands = [
|
||||||
|
{command:'start',script:'echo "Hello"',description:'Start conversation'},
|
||||||
|
{command:'help',script:'echo "Try https://t.me/openipc"',description:'Request help'},
|
||||||
|
{command:'info',script:'cat /etc/os-release',description:'Information about system'},
|
||||||
|
{command:'snap',script:'snapshot4cron.sh && send2telegram.sh -c $chat_id -p /tmp/snapshot4cron.jpg -i',description:'Take a snapshot'},
|
||||||
|
{command:'stop',script:'/etc/init.d/S93telegrambot stop',description:'Stop the bot'},
|
||||||
|
{command:'yadisk',script:'send2yadisk.sh && send2telegram.sh -c $chat_id -m "Sent to Yandex Disk"',description:'Send snapshot to Yandex Disk'},
|
||||||
|
{command:'restart',script:'/etc/init.d/S93telegrambot restart',description:'Restart the bot'},
|
||||||
|
]
|
||||||
|
function resetBotCommands() {
|
||||||
|
$$('.bot-commands input[type=text]').forEach(e => e.value = '');
|
||||||
|
let i=0;
|
||||||
|
default_commands.forEach(c => {
|
||||||
|
$('#telegrambot_command_'+i).value = c.command;
|
||||||
|
$('#telegrambot_script_'+i).value = c.script;
|
||||||
|
$('#telegrambot_description_'+i).value = c.description;
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$('#reset_commands').addEventListener('click', resetBotCommands);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="vtun"
|
||||||
|
plugin_name="Виртуальный туннель"
|
||||||
|
page_title="Виртуальная туннель"
|
||||||
|
service_file=/etc/init.d/S98vtun
|
||||||
|
conf_file=/tmp/vtund.conf
|
||||||
|
|
||||||
|
if [ -n "$POST_action" ] && [ "$POST_action" = "reset" ]; then
|
||||||
|
killall tunnel
|
||||||
|
killall vtund
|
||||||
|
rm $conf_file
|
||||||
|
rm $service_file
|
||||||
|
redirect_to "$SCRIPT_NAME" "danger" "Туннель не работает"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$POST_vtun_host" ]; then
|
||||||
|
echo -e "#!/bin/sh\n\ntunnel $POST_vtun_host\n" >$service_file
|
||||||
|
chmod +x $service_file
|
||||||
|
$service_file
|
||||||
|
redirect_to "$SCRIPT_NAME" "success" "Туннель поднят"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col col-lg-4">
|
||||||
|
<% if [ -f "$conf_file" ]; then %>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<h4>Виртуальный туннель запущен</h4>
|
||||||
|
<p>Используйте следующие учетные данные для настройки удаленного доступа через активный виртуальный туннель:</p>
|
||||||
|
<dl class="mb-0">
|
||||||
|
<dt>ID туннеля</dt>
|
||||||
|
<dd><%= ${network_macaddr//:/} | tr a-z A-Z %></dd>
|
||||||
|
<dt>Пароль</dt>
|
||||||
|
<dd><% grep password $conf_file | xargs | cut -d' ' -f2 | sed 's/;$//' %>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<h3>Настройки</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% if [ -f "$service_file" ]; then %>
|
||||||
|
<% field_hidden "action" "Сброс" %>
|
||||||
|
<% button_submit "Сбросить конфигурацию" %>
|
||||||
|
<% else %>
|
||||||
|
<% field_text "vtun_host" "Хост виртуального туннеля" "Ваш адрес сервера виртуального туннеля." %>
|
||||||
|
<% button_submit %>
|
||||||
|
<% fi %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,142 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="zerotier"
|
||||||
|
plugin_name="ZeroTier"
|
||||||
|
page_title="ZeroTier"
|
||||||
|
params="enabled nwid"
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
service_file=/etc/init.d/S90zerotier
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
zt_cli_bin=/usr/sbin/zerotier-cli
|
||||||
|
zt_one_bin=/usr/sbin/zerotier-one
|
||||||
|
|
||||||
|
[ ! -f "$zt_cli_bin" ] &&
|
||||||
|
redirect_to "/" "danger" "Клиент ZerotierOne не является частью вашей прошивки."
|
||||||
|
|
||||||
|
[ ! -f "$zt_one_bin" ] &&
|
||||||
|
redirect_to "/" "danger" "${zt_one_bin} файл не найден."
|
||||||
|
|
||||||
|
[ ! -f "$service_file" ] &&
|
||||||
|
redirect_to "/" "danger" "${service_file} файл не найден."
|
||||||
|
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
include $config_file
|
||||||
|
|
||||||
|
[ -n "$zerotier_nwid" ] &&
|
||||||
|
zt_network_config_file="/var/lib/zerotier-one/networks.d/${zerotier_nwid}.conf"
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
create)
|
||||||
|
# parse values from parameters
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
if [ "true" = "$zerotier_enabled" ]; then
|
||||||
|
[ -z "$zerotier_nwid" ] &&
|
||||||
|
flash_append "danger" "Идентификатор сети ZeroTier не может быть пустым.." && error=1
|
||||||
|
[ "${#zerotier_nwid}" -ne "16" ] &&
|
||||||
|
flash_append "danger" "Идентификатор сети ZeroTier должен состоять из 16 цифр.." && error=2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "Конфигурация ${plugin_name} обновлена."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
start|open)
|
||||||
|
$service_file start >&2
|
||||||
|
redirect_back # "success" "Сервис запущен"
|
||||||
|
;;
|
||||||
|
stop|close)
|
||||||
|
$service_file stop >&2
|
||||||
|
redirect_back # "danger" "Сервис не работает"
|
||||||
|
;;
|
||||||
|
join)
|
||||||
|
$zt_cli_bin join $zerotier_nwid >&2
|
||||||
|
while [ -z $(grep nwid "$zt_network_config_file") ]; do sleep 1; done
|
||||||
|
redirect_back
|
||||||
|
;;
|
||||||
|
leave)
|
||||||
|
$zt_cli_bin leave $zerotier_nwid >&2
|
||||||
|
redirect_back
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
redirect_back "danger" "Неизвестное действие $POST_action!"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col col-lg-4">
|
||||||
|
<h3>Settings</h3>
|
||||||
|
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Создать" %>
|
||||||
|
<% field_switch "zerotier_enabled" "Включить сеть ZeroTier при перезапуске" %>
|
||||||
|
<% field_text "zerotier_nwid" "Идентификатор сети ZeroTier" "У вас его нет? Получите один в <a href=\"https://my.zerotier.com/\">my.zerotier.com</a>" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<% zerotier-cli info >/dev/null; if [ $? -eq 0 ]; then %>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<h5>Туннель ZeroTier открытn</h5>
|
||||||
|
|
||||||
|
<% if [ -f "$zt_network_config_file" ]; then %>
|
||||||
|
<% zt_id="$(grep ^nwid= ${zt_network_config_file} | cut -d= -f2)" %>
|
||||||
|
<% zt_name="$(grep ^n= ${zt_network_config_file} | cut -d= -f2)" %>
|
||||||
|
<% if [ -n "$zt_id" ] && [ -n "$zt_name" ]; then %>
|
||||||
|
<p>Используйте следующие учетные данные для настройки удаленного доступа через активный виртуальный туннель:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>NWID: <%= $zt_id %></dd>
|
||||||
|
<dt>Name: <%= $zt_name %></dd>
|
||||||
|
</dl>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Выйти" %>
|
||||||
|
<% button_submit "Выйти из сети" "danger" %>
|
||||||
|
</form>
|
||||||
|
<% fi %>
|
||||||
|
<% else %>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Подключиться" %>
|
||||||
|
<% button_submit "Присоединяйтесь к сети" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Остановить" %>
|
||||||
|
<% button_submit "Закрыть туннель" "danger" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h4>Туннель ZeroTier закрыт</h4>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Старт" %>
|
||||||
|
<% button_submit "Открыть туннель" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Предпросмотр камеры"
|
||||||
|
|
||||||
|
size=$(yaml-cli -g .mjpeg.size); [ -z "$size" ] && size="640x480"
|
||||||
|
size_w=${size%x*}
|
||||||
|
size_h=${size#*x}
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row preview">
|
||||||
|
<div class="col-md-8 col-xl-9 col-xxl-9 position-relative mb-3">
|
||||||
|
<% preview 1 %>
|
||||||
|
<p class="small text-body-secondary">Изображение выше обновляется раз в секунду и может выглядеть прерывисто.
|
||||||
|
Чтобы увидеть плавную видеотрансляцию с камеры, используйте одну из <a href="majestic-endpoints.cgi" target="_blank">конечных точек</a>.
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-xl-3 col-xxl-3">
|
||||||
|
<div class="d-grid gap-2 mb-3">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<img src="/a/light-off.svg" alt="Image: Night mode indicator" id="night-mode-status">
|
||||||
|
</div>
|
||||||
|
<button class="form-control btn btn-primary text-start" type="button" id="toggle-night-mode">Сменить ночной режим</button>
|
||||||
|
<div class="input-group-text">
|
||||||
|
<a href="majestic-settings.cgi?tab=nightMode" title="Настройки ночного режима"><img src="/a/gear.svg" alt="Gear"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<button class="form-control btn btn-primary text-start" type="button" data-sendto="telegram">Отправить в Телеграм</button>
|
||||||
|
<div class="input-group-text">
|
||||||
|
<a href="plugin-send2telegram.cgi" title="Настройки телеграм-бота"><img src="/a/gear.svg" alt="Gear"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<button class="form-control btn btn-primary text-start" type="button" data-sendto="yadisk">Отправить на яндекс диск</button>
|
||||||
|
<div class="input-group-text">
|
||||||
|
<a href="plugin-send2yadisk.cgi" title="Настройки Яндекс Диска"><img src="/a/gear.svg" alt="Gear"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-danger small">
|
||||||
|
Функция PTZ не готова. Пожалуйста примите к сведению <a href="https://t.me/OpenIPC">возможность поддержки дальнейшего развития</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const network_address = "<%= $network_address %>";
|
||||||
|
|
||||||
|
<% [ "true" != "$telegram_enabled" ] && echo "\$('button[data-sendto=telegram]').disabled = true;" %>
|
||||||
|
<% [ "true" != "$yadisk_enabled" ] && echo "\$('button[data-sendto=yadisk]').disabled = true;" %>
|
||||||
|
|
||||||
|
function reqListener(data) {
|
||||||
|
console.log(data.responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
$$("a[id^=pan-],a[id^=zoom-]").forEach(el => {
|
||||||
|
el.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
alert("Извините, эта функция пока не работает!");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#toggle-night-mode")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
$('#night-mode-status').src = ($('#night-mode-status').src.split("/").pop() == "light-on.svg") ? "/a/light-off.svg" : "/a/light-on.svg";
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("POST", "/cgi-bin/night.cgi");
|
||||||
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
xhr.send("mode=toggle");
|
||||||
|
});
|
||||||
|
|
||||||
|
$$("button[data-sendto]").forEach(el => el.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!confirm("Are you sure?")) return false;
|
||||||
|
const tgt = event.target.dataset["sendto"];
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "/cgi-bin/send.cgi?to=" + tgt);
|
||||||
|
xhr.send();
|
||||||
|
}))
|
||||||
|
|
||||||
|
$("#speed")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.target.src = (event.target.src.split("/").pop() == "speed-slow.svg") ? "/a/speed-fast.svg" : "/a/speed-slow.svg";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
echo "HTTP/1.1 302 Moved Temporarily
|
||||||
|
Date: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
|
||||||
|
Server: $SERVER_SOFTWARE
|
||||||
|
Content-type: text/html; charset=UTF-8
|
||||||
|
Cache-Control: no-store
|
||||||
|
Pragma: no-cache
|
||||||
|
Location: /wait.html
|
||||||
|
Status: 302 Moved Temporarily
|
||||||
|
"
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
umount -a -t nfs -l
|
||||||
|
reboot -f
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Перезагрузка устройства" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-md-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>Перезагрузка камеры</h4>
|
||||||
|
<p>Перезагрузите камеру, чтобы применить новые настройки. Это также удалит все данные о разделах, смонтированных в системной памяти, например. /tmp.</p>
|
||||||
|
<% button_reboot %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<%in p/reset-firmware.cgi %>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>Сбросить настройки Маджестик</h4>
|
||||||
|
<p>Восстановить файл конфигурации Majestic <code>/etc/majestic.yaml</code> до своего первозданного состояния. Все изменения будут потеряны!
|
||||||
|
Вы можете захотеть <a href="majestic-config-actions.cgi">сделать резервную копию последней конфигурации</a> перед сбросом.</p>
|
||||||
|
<% button_mj_reset %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
[ -z "$GET_f" ] && append_flash "danger" "Нечего восстанавливать." && error=1
|
||||||
|
|
||||||
|
file=$GET_f
|
||||||
|
[ ! -f "/rom/${file}" ] && append_flash "danger" "Файл /rom/${file} не найден!" && error=1
|
||||||
|
|
||||||
|
[ -n "$error" ] && redirect_back
|
||||||
|
|
||||||
|
cp "/rom/${file}" "${file}"
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
redirect_back "success" "Файл ${file} восстановлен до настроек по умолчанию."
|
||||||
|
else
|
||||||
|
redirect_back "danger" "Невозможно восстановить ${file}!"
|
||||||
|
fi
|
||||||
|
%>
|
|
@ -0,0 +1,103 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="SD-карта" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<%
|
||||||
|
ls /dev/mmc* >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
%>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>Эта камера поддерживает SD-карту?</h4>
|
||||||
|
<p>В вашей камере нет слота для SD-карты или SD-карта не вставлена.</p>
|
||||||
|
</div>
|
||||||
|
<%
|
||||||
|
else
|
||||||
|
card_device="/dev/mmcblk0"
|
||||||
|
card_partition="${card_device}p1"
|
||||||
|
mount_point="${card_partition//dev/mnt}"
|
||||||
|
error=""
|
||||||
|
_o=""
|
||||||
|
|
||||||
|
if [ -n "$POST_doFormatCard" ]; then
|
||||||
|
%>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>ВНИМАНИЕ! Форматирование SD-карты требует времени.</h4>
|
||||||
|
<p>Пожалуйста, не обновляйте эту страницу. Дождитесь завершения форматирования раздела!</p>
|
||||||
|
</div>
|
||||||
|
<%
|
||||||
|
if [ "$(grep $card_partition /etc/mtab)" ]; then
|
||||||
|
_c="umount $card_partition"
|
||||||
|
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||||
|
[ $? -ne 0 ] && error="Не удается размонтировать раздел SD-карты."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
_c="echo -e 'o\nn\np\n1\n\n\nw'|fdisk $card_device"
|
||||||
|
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||||
|
[ $? -ne 0 ] && error="Не удается создать раздел SD-карты."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
_c="mkfs.vfat -v -n OpenIPC $card_partition"
|
||||||
|
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||||
|
[ $? -ne 0 ] && error="Не удается отформатировать раздел SD-карты."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ] && [ ! -d "$mount_point" ]; then
|
||||||
|
_c="mkdir -p $mount_point"
|
||||||
|
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||||
|
[ $? -ne 0 ] && error="Не удается создать точку монтирования SD-карты."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
_c="mount $card_partition $mount_point"
|
||||||
|
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||||
|
[ $? -ne 0 ] && error="Не удается перемонтировать раздел SD-карты."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$error" ]; then
|
||||||
|
report_error "$error"
|
||||||
|
[ -n "$_c" ] && report_command_info "$_c" "$_o"
|
||||||
|
else
|
||||||
|
report_log "$_o"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<a class="btn btn-primary" href="/">DВернуться на главную</a>
|
||||||
|
<% else %>
|
||||||
|
<h4>Разделы SD-карты</h4>
|
||||||
|
<%
|
||||||
|
partitions=$(df -h | grep 'dev/mmc')
|
||||||
|
echo "<pre class=\"small\">${partitions}</pre>"
|
||||||
|
|
||||||
|
if [ -n "$partitions" ]; then
|
||||||
|
%>
|
||||||
|
<h4>Просмотр файлов на этих разделах</h4>
|
||||||
|
<div class="mb-4">
|
||||||
|
<%
|
||||||
|
IFS=$'\n'
|
||||||
|
for i in $partitions; do
|
||||||
|
# _mount="${i##* }"
|
||||||
|
_mount=$(echo $i | awk '{print $6}')
|
||||||
|
echo "<a href=\"file-manager.cgi?cd=${_mount}\" class=\"btn btn-primary\">${_mount}</a>"
|
||||||
|
unset _mount
|
||||||
|
done
|
||||||
|
IFS=$IFS_ORIG
|
||||||
|
unset _partitions
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
|
||||||
|
<h4>Отформатировать SD-карту</h4>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4>ВНИМАНИЕ! Форматирование уничтожит все данные на SD-карте.</h4>
|
||||||
|
<p>Убедитесь, что у вас есть резервная копия, если вы собираетесь использовать данные в будущем.</p>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "doFormatCard" "true" %>
|
||||||
|
<% button_submit "Форматировать SD-карту" "danger" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<%
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
target="$GET_to"
|
||||||
|
if [ -n "$(echo "telegram yadisk" | sed -n "/\b${target}\b/p")" ]; then
|
||||||
|
/usr/sbin/snapshot4cron.sh -f >/dev/null
|
||||||
|
[ "openwall" = "$target" ] && opts="-f"
|
||||||
|
/usr/sbin/send2${target}.sh ${opts} >/dev/null
|
||||||
|
redirect_back "success" "Отправить в ${target}."
|
||||||
|
elif [ "pastebin" = "$target" ]; then
|
||||||
|
if [ "mjlog" = "$GET_file" ]; then
|
||||||
|
_t=$(mktemp)
|
||||||
|
logread | grep 'user.info majestic' >$_t
|
||||||
|
_url=$(/usr/sbin/send2${target}.sh $_t)
|
||||||
|
rm $_t
|
||||||
|
unset _t
|
||||||
|
redirect_to $_url
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
redirect_back "danger" "Неизвестная цель ${target}!"
|
||||||
|
fi
|
||||||
|
%>
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/haserl --upload-limit=200 --upload-dir=/tmp
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Драйвер датчика и конфигурация"
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
error=""
|
||||||
|
|
||||||
|
if [ -n "$POST_sensor_driver_file" ]; then
|
||||||
|
type="driver"
|
||||||
|
magicnum="7f454c460101"
|
||||||
|
file="$POST_sensor_driver_file"
|
||||||
|
file_name="$POST_sensor_driver_file_name"
|
||||||
|
file_path="$POST_sensor_driver_file_path"
|
||||||
|
|
||||||
|
if [ -z "$file_name" ]; then
|
||||||
|
error="Файл не найден! Вы не забыли загрузить?"
|
||||||
|
elif [ "$magicnum" != $(xxd -p -l 6 $file) ]; then
|
||||||
|
error="Магический номер файла не совпадает. Вы загрузили неправильный файл?"
|
||||||
|
elif [ -f "/usr/lib/sensors/${file_name}" ]; then
|
||||||
|
error="Файл уже существует!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$POST_sensor_config_file" ]; then
|
||||||
|
type="config"
|
||||||
|
file="$POST_sensor_config_file"
|
||||||
|
file_name="$POST_sensor_config_file_name"
|
||||||
|
file_path="$POST_sensor_config_file_path"
|
||||||
|
if [ -z "$file_name" ]; then
|
||||||
|
error="Файл не найден! Вы не забыли загрузить?"
|
||||||
|
elif [ -n $(grep "\[sensor\]" $file) ]; then
|
||||||
|
error="Магический номер файла не совпадает. Вы загрузили неправильный файл?"
|
||||||
|
elif [ -f "/etc/sensors/${file_name}" ]; then
|
||||||
|
error="Файл уже существует!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
case "$type" in
|
||||||
|
driver)
|
||||||
|
mv "$file_path" "/usr/lib/sensors/${file_name}"
|
||||||
|
redirect_to $SCRIPT_NAME "success" "Драйвер датчика загружен."
|
||||||
|
;;
|
||||||
|
config)
|
||||||
|
mv "$file_path" "/etc/sensors/${file_name}"
|
||||||
|
redirect_to $SCRIPT_NAME "success" "Конфигурация датчика загружена."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<% [ -n "$error" ] && report_error "$error" %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Драйверы датчиков</h3>
|
||||||
|
<% ex "ls /usr/lib/sensors/" %>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Загрузить драйвер датчика</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_file "sensor_driver_file" "Файл драйвера датчика" %>
|
||||||
|
<% button_submit "Загрузить файл" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Конфигурация сенсора</h3>
|
||||||
|
<% ex "ls /etc/sensors/" %>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Загрузить конфигурацию сенсора</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_file "sensor_config_file" "Файл конфигурации датчика" %>
|
||||||
|
<% button_submit "Загрузить файл" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<% page_title="Статус устройства" %>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Камера</h3>
|
||||||
|
<h5>Система</h5>
|
||||||
|
<dl class="small list">
|
||||||
|
<dt>Процессор</dt>
|
||||||
|
<dd><%= $soc %></dd>
|
||||||
|
<dt>Семейство</dt>
|
||||||
|
<dd><%= $soc_family %></dd>
|
||||||
|
<dt>Тип сенсора</dt>
|
||||||
|
<dd><%= $sensor_ini %></dd>
|
||||||
|
<dt>Объём памяти</dt>
|
||||||
|
<dd><%= $flash_size %> MB</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<h3>Система</h3>
|
||||||
|
<h5>Прошивка</h5>
|
||||||
|
<dl class="small list">
|
||||||
|
<dt>Версия</dt>
|
||||||
|
<dd><%= "${fw_version}-${fw_variant}" %></dd>
|
||||||
|
<dt>Билд</dt>
|
||||||
|
<dd><%= $fw_build %></dd>
|
||||||
|
<dt>Majestic</dt>
|
||||||
|
<dd><%= $mj_version %></dd>
|
||||||
|
<dt>Имя устройства</dt>
|
||||||
|
<dd><%= $network_hostname %></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%
|
||||||
|
_s=$(df | grep /overlay | xargs | cut -d' ' -f5)
|
||||||
|
%>
|
||||||
|
<div class="alert alert-primary">
|
||||||
|
<h5>Раздел Оверлея заполнен на <%= $_s %>.</h5>
|
||||||
|
<% progressbar "${_s/%/}" %>
|
||||||
|
</div>
|
||||||
|
<%in p/reset-firmware.cgi %>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,110 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
editor_file="$POST_editor_file"
|
||||||
|
editor_text="$POST_editor_text"
|
||||||
|
editor_backup="$POST_editor_backup"
|
||||||
|
|
||||||
|
# strip carriage return (\u000D) characters
|
||||||
|
editor_text=$(echo "$editor_text" | sed s/\\r//g)
|
||||||
|
|
||||||
|
case "$POST_action" in
|
||||||
|
restore)
|
||||||
|
if [ ! -f "$editor_file" ]; then
|
||||||
|
redirect_to "${SCRIPT_NAME}?f=${editor_file}" "danger" "Файл не найден!"
|
||||||
|
elif [ ! -f "$editor_file.backup" ]; then
|
||||||
|
redirect_to "${SCRIPT_NAME}?f=${editor_file}" "danger" "Файл не найден!"
|
||||||
|
else
|
||||||
|
mv "$editor_file.backup" "$editor_file"
|
||||||
|
redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "Файл восстановлен из резервной копии."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
save)
|
||||||
|
if [ -z "$editor_text" ]; then
|
||||||
|
flash_save "warning" "Пустая полезная нагрузка. Файл не сохранен!"
|
||||||
|
else
|
||||||
|
if [ -n "$editor_backup" ]; then
|
||||||
|
cp "$editor_file" "${editor_file}.backup"
|
||||||
|
else
|
||||||
|
[ -f "${editor_file}.backup" ] && rm "${editor_file}.backup"
|
||||||
|
fi
|
||||||
|
echo "$editor_text" >"$editor_file"
|
||||||
|
redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "Файл сохранён."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
flash_save "danger" "UNKNOWN ACTION: $POST_action"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
editor_file="$GET_f"
|
||||||
|
if [ ! -f "$editor_file" ]; then
|
||||||
|
flash_save "danger" "Файл не найден!"
|
||||||
|
elif [ -n "$editor_file" ]; then
|
||||||
|
if [ "b" = "$( (cat -v "$editor_file" | grep -q "\^@") && echo "b" )" ]; then
|
||||||
|
flash_save "danger" "Не текстовый файл!"
|
||||||
|
elif [ "$(stat -c%s $editor_file)" -gt "102400" ]; then
|
||||||
|
flash_save "danger" "Загруженный файл слишком большой!"
|
||||||
|
else
|
||||||
|
editor_text="$(cat $editor_file | sed "s/&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
page_title="Текстовый редактор"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<% tab_lap "edit" "Редактор" %>
|
||||||
|
<% tab_lap "file" "Файл" %>
|
||||||
|
<% if [ -f "${editor_file}.backup" ]; then %>
|
||||||
|
<% tab_lap "back" "Восстановление" %>
|
||||||
|
<% tab_lap "diff" "Различие" %>
|
||||||
|
<% fi %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content p-2" id="tab-content">
|
||||||
|
<div id="edit-tab-pane" role="tabpanel" class="tab-pane fade show active" aria-labelledby="edit-tab" tabindex="0">
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" class="mb-4">
|
||||||
|
<% field_hidden "action" "Сохранить" %>
|
||||||
|
<% field_hidden "editor_file" "$editor_file" %>
|
||||||
|
<% field_textarea "editor_text" "Содержимое файла" %>
|
||||||
|
<p class="boolean"><span class="form-check form-switch">
|
||||||
|
<input type="checkbox" id="editor_backup" name="editor_backup" value="true" class="form-check-input" role="switch">
|
||||||
|
<label for="editor_backup" class="form-label form-check-label">Создать резервный файл</label>
|
||||||
|
</span></p>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="file-tab-pane" role="tabpanel" class="tab-pane fade" aria-labelledby="file-tab" tabindex="0">
|
||||||
|
<% ex "cat -t $editor_file" %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if [ -f "${editor_file}.backup" ]; then %>
|
||||||
|
<div id="back-tab-pane" role="tabpanel" class="tab-pane fade" aria-labelledby="back-tab" tabindex="0">
|
||||||
|
<% ex "cat -t ${editor_file}.backup" %>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Перезагрузка" %>
|
||||||
|
<% field_hidden "editor_file" "$editor_file" %>
|
||||||
|
<% button_submit "Восстановить" "danger" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="diff-tab-pane" role="tabpanel" class="tab-pane fade" aria-labelledby="diff-tab" tabindex="0">
|
||||||
|
<h4>Изменения по сравнению с предыдущей версией</h4>
|
||||||
|
<%
|
||||||
|
# it's ugly but shows non-printed characters (^M/^I)
|
||||||
|
_n=$(basename $editor_file)
|
||||||
|
cat -t $editor_file >/tmp/${_n}.np
|
||||||
|
cat -t ${editor_file}.backup >/tmp/${_n}.backup.np
|
||||||
|
pre "$(diff -s -d -U0 /tmp/${_n}.backup.np -L ${editor_file}.backup /tmp/${_n}.np -L $editor_file)"
|
||||||
|
rm /tmp/${_n}.np /tmp/${_n}.backup.np
|
||||||
|
unset _n
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="time"
|
||||||
|
page_title="Время"
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
reset)
|
||||||
|
cp /rom/etc/ntp.conf /etc/ntp.conf
|
||||||
|
redirect_back "success" "Конфигурация сброшена к заводским настройкам прошивки."
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
# check for mandatory data
|
||||||
|
[ -z "$POST_tz_name" ] && redirect_to $SCRIPT_NAME "warning" "Пустое название часового пояса. Пропустить."
|
||||||
|
[ -z "$POST_tz_data" ] && redirect_to $SCRIPT_NAME "warning" "Пустое значение часового пояса. Пропустить."
|
||||||
|
|
||||||
|
[ "$tz_data" != "$POST_tz_data" ] && echo "${POST_tz_data}" >/etc/TZ
|
||||||
|
[ "$tz_name" != "$POST_tz_name" ] && echo "${POST_tz_name}" >/etc/timezone
|
||||||
|
|
||||||
|
tmp_file=/tmp/ntp.conf
|
||||||
|
:>$tmp_file
|
||||||
|
for _i in 0 1 2 3; do
|
||||||
|
eval _s="\$POST_ntp_server_${_i}"
|
||||||
|
[ -n "$_s" ] && echo "server ${_s} iburst" >>$tmp_file
|
||||||
|
done
|
||||||
|
unset _i; unset _s
|
||||||
|
mv $tmp_file /etc/ntp.conf
|
||||||
|
redirect_back "success" "Конфигурация обновлена."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_to $SCRIPT_NAME "success" "Часовой пояс обновлен."
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Обновить" %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-2 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4>Часовой пояс</h4>
|
||||||
|
<datalist id="tz_list"></datalist>
|
||||||
|
<p class="string">
|
||||||
|
<label for="tz_name" class="form-label">Название часового пояса</label>
|
||||||
|
<input type="text" id="tz_name" name="tz_name" value="<%= $tz_name %>" class="form-control" list="tz_list">
|
||||||
|
<span class="hint text-secondary">Начните вводить название ближайшего крупного города в поле выше, затем выберите один из доступных вариантов.</span>
|
||||||
|
</p>
|
||||||
|
<p class="string">
|
||||||
|
<label for="tz_data" class="form-label">Строка зоны</label>
|
||||||
|
<input type="text" id="tz_data" name="tz_data" value="<%= $tz_data %>" class="form-control" readonly>
|
||||||
|
<span class="hint text-secondary">Управляющая строка часового пояса, выбранного выше. Поле только для чтения, только для мониторинга.</span>
|
||||||
|
</p>
|
||||||
|
<p><a href="#" id="frombrowser">Получить часовой пояс из браузера</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h4>Синхронизация времени</h4>
|
||||||
|
<%
|
||||||
|
for _i in 0 1 2 3; do
|
||||||
|
_x=$(expr $_i + 1)
|
||||||
|
eval ntp_server_${_i}="$(sed -n ${_x}p /etc/ntp.conf | cut -d' ' -f2)"
|
||||||
|
field_text "ntp_server_${_i}" "NTP Server $(( _i + 1 ))"
|
||||||
|
done; unset _i; unset _x
|
||||||
|
%>
|
||||||
|
<p id="sync-time-wrapper"><a href="#" id="sync-time">Синхронизировать время</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<% if [ "$(diff -q -- "/rom${config_file}" "$config_file")" ]; then %>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" class="mt-4">
|
||||||
|
<% field_hidden "action" "reset" %>
|
||||||
|
<% button_submit "Восстановить настройки прошивки по умолчанию" "danger" %>
|
||||||
|
</form>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script src="/a/tz.js"></script>
|
||||||
|
<script>
|
||||||
|
$('#sync-time').addEventListener('click', event => {
|
||||||
|
event.preventDefault();
|
||||||
|
fetch('/cgi-bin/j/sync-time.cgi')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
p = document.createElement('p');
|
||||||
|
p.classList.add('alert', 'alert-' + json.result);
|
||||||
|
p.textContent = json.message;
|
||||||
|
$('#sync-time-wrapper').replaceWith(p);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Инструменты мониторинга"
|
||||||
|
tools_action="ping"
|
||||||
|
tools_target="4.2.2.1"
|
||||||
|
tools_interface="auto"
|
||||||
|
tools_packet_size="56" # 56-1500 for ping, 38-32768 for trace
|
||||||
|
tools_duration="5"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col col-md-4">
|
||||||
|
<h3>Качество пинга</h3>
|
||||||
|
<form>
|
||||||
|
<% field_select "tools_action" "Action" "ping,trace" %>
|
||||||
|
<% field_text "tools_target" "Целевое полное доменное имя или IP-адрес" %>
|
||||||
|
<% field_select "tools_interface" "Сетевой интерфейс" "авто,${interfaces}" %>
|
||||||
|
<% field_number "tools_packet_size" "Размер пакета" "56,65535,1" "Байт" %>
|
||||||
|
<% field_number "tools_duration" "Количество пакетов" "1,30,1" %>
|
||||||
|
<% button_submit "Выполнить" %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-8">
|
||||||
|
<div id="output-wrapper"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('form').addEventListener('submit', event => {
|
||||||
|
event.preventDefault();
|
||||||
|
$('form input[type=submit]').disabled = true;
|
||||||
|
|
||||||
|
if ($('#tools_action').value == 'ping') {
|
||||||
|
cmd = 'ping -s ' + $('#tools_packet_size').value;
|
||||||
|
if ($('#tools_interface').value !== 'auto') cmd =+ ' -I ' + $('#tools_interface').value;
|
||||||
|
cmd += ' -c ' + $('#tools_duration').value + ' ' + $('#tools_target').value;
|
||||||
|
} else {
|
||||||
|
cmd = 'traceroute -q ' + $('#tools_duration').value + ' -w 1';
|
||||||
|
if ($('#tools_interface').value !== 'auto') cmd =+ ' -i ' + $('#tools_interface').value;
|
||||||
|
cmd += ' ' + $('#tools_target').value + ' ' + $('#tools_packet_size').value;
|
||||||
|
}
|
||||||
|
|
||||||
|
el = document.createElement('pre')
|
||||||
|
el.id = "output";
|
||||||
|
el.dataset['cmd'] = cmd;
|
||||||
|
|
||||||
|
h6 = document.createElement('h6')
|
||||||
|
h6.textContent = '# ' + cmd;
|
||||||
|
|
||||||
|
$('#output-wrapper').innerHTML = '';
|
||||||
|
$('#output-wrapper').appendChild(h6);
|
||||||
|
$('#output-wrapper').appendChild(el);
|
||||||
|
|
||||||
|
async function* makeTextFileLineIterator(url) {
|
||||||
|
const td = new TextDecoder('utf-8');
|
||||||
|
const response = await fetch(url);
|
||||||
|
const rd = response.body.getReader();
|
||||||
|
let { value: chunk, done: readerDone } = await rd.read();
|
||||||
|
chunk = chunk ? td.decode(chunk) : '';
|
||||||
|
const re = /\n|\r|\r\n/gm;
|
||||||
|
let startIndex = 0;
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
for (;;) {
|
||||||
|
result = re.exec(chunk);
|
||||||
|
if (!result) {
|
||||||
|
if (readerDone) break;
|
||||||
|
let remainder = chunk.substr(startIndex);
|
||||||
|
({value: chunk, done: readerDone} = await rd.read());
|
||||||
|
chunk = remainder + (chunk ? td.decode(chunk) : '');
|
||||||
|
startIndex = re.lastIndex = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
yield chunk.substring(startIndex, result.index);
|
||||||
|
startIndex = re.lastIndex;
|
||||||
|
}
|
||||||
|
if (startIndex < chunk.length) yield chunk.substr(startIndex);
|
||||||
|
} finally {
|
||||||
|
if ('true' === el.dataset['reboot']) {
|
||||||
|
window.location.href = '/cgi-bin/reboot.cgi'
|
||||||
|
} else {
|
||||||
|
el.innerHTML += '\n--- finished ---\n';
|
||||||
|
}
|
||||||
|
$('form input[type=submit]').disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
for await (let line of makeTextFileLineIterator('/cgi-bin/j/run.cgi?cmd=' + btoa(el.dataset['cmd']))) {
|
||||||
|
const re1 = /\[1;(\d+)m/;
|
||||||
|
const re2 = /\[0m/;
|
||||||
|
line = line.replace(re1, '<span class="ansi-$1">').replace(re2, '</span>')
|
||||||
|
el.innerHTML += line + '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/haserl --upload-limit=100 --upload-dir=/tmp
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
plugin="webui"
|
||||||
|
plugin_name="User interface settings"
|
||||||
|
page_title="Настройка Веб-интерфейса"
|
||||||
|
|
||||||
|
tmp_file=/tmp/${plugin}.conf
|
||||||
|
|
||||||
|
config_file="${ui_config_dir}/${plugin}.conf"
|
||||||
|
[ ! -f "$config_file" ] && touch $config_file
|
||||||
|
|
||||||
|
locale_file=/etc/webui/locale
|
||||||
|
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
access)
|
||||||
|
new_password="$POST_ui_password_new"
|
||||||
|
[ -z "$new_password" ] && redirect_to $SCRIPT_NAME "danger" "Пароль не может быть пустым!"
|
||||||
|
|
||||||
|
echo "root:${new_password}" | chpasswd
|
||||||
|
update_caminfo
|
||||||
|
|
||||||
|
redirect_to "/" "success" "Пароль успешно обновлён."
|
||||||
|
;;
|
||||||
|
|
||||||
|
interface)
|
||||||
|
params="level theme"
|
||||||
|
for _p in $params; do
|
||||||
|
eval ${plugin}_${_p}=\$POST_${plugin}_${_p}
|
||||||
|
sanitize "${plugin}_${_p}"
|
||||||
|
done; unset _p
|
||||||
|
|
||||||
|
[ -z "$webui_level" ] && webui_level="user"
|
||||||
|
|
||||||
|
if [ -z "$error" ]; then
|
||||||
|
# create temp config file
|
||||||
|
:>$tmp_file
|
||||||
|
for _p in $params; do
|
||||||
|
echo "${plugin}_${_p}=\"$(eval echo \$${plugin}_${_p})\"" >>$tmp_file
|
||||||
|
done; unset _p
|
||||||
|
mv $tmp_file $config_file
|
||||||
|
|
||||||
|
update_caminfo
|
||||||
|
redirect_back "success" "${plugin_name} конфигурация обновлена."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
locale)
|
||||||
|
locale="$POST_ui_language" # set language.
|
||||||
|
# upload new language and switch to it. overrides aboveset language.
|
||||||
|
_fname="$POST_ui_locale_file_name"
|
||||||
|
if [ -n "$_fname" ]; then
|
||||||
|
mv "$POST_ui_locale_file_path" /var/www/lang/$_fname
|
||||||
|
locale=${_fname%%.*}
|
||||||
|
fi
|
||||||
|
# save new language settings and reload locale
|
||||||
|
[ -z "$locale" ] && locale="en"
|
||||||
|
echo "$locale" >$locale_file
|
||||||
|
reload_locale
|
||||||
|
update_caminfo
|
||||||
|
redirect_to $SCRIPT_NAME "success" "Локализация успешно обновлена."
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
redirect_to $SCRIPT_NAME "danger" "НЕИЗВЕСТНОЕ ДЕЙСТВИЕ: $POST_action"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
page_title="Настройка Веб-интерфейса"
|
||||||
|
|
||||||
|
# data for form fields
|
||||||
|
ui_username="$USER"
|
||||||
|
ui_language="$locale"
|
||||||
|
|
||||||
|
ui_locales="en|English"
|
||||||
|
if [ -d /var/www/lang/ ]; then
|
||||||
|
for i in $(ls -1 /var/www/lang/); do
|
||||||
|
code="$(basename $i)"; code="${code%%.sh}"
|
||||||
|
name="$(sed -n 2p $i|sed "s/ /_/g"|cut -d: -f2)"
|
||||||
|
ui_locales="${ui_locales},${code}|${name}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Доступ</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Доступ" %>
|
||||||
|
<p class="string">
|
||||||
|
<label for="ui_username" class="form-label">Имя пользователя</label>
|
||||||
|
<input type="text" id="ui_username" name="ui_username" value="<%= $ui_username %>" class="form-control" autocomplete="username" disabled>
|
||||||
|
</p>
|
||||||
|
<% field_password "ui_password_new" "Пароль" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Детали интерфейса</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||||
|
<% field_hidden "action" "Интерфейс" %>
|
||||||
|
<% field_select "webui_level" "Уровень" "Пользователь,Администратор" %>
|
||||||
|
<% field_select "webui_theme" "Тема" "Светлая,Тёмная" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<div class="col">
|
||||||
|
<h3>Локализация</h3>
|
||||||
|
<form action="<%= $SCRIPT_NAME %>" method="post" enctype="multipart/form-data">
|
||||||
|
<% field_hidden "action" "Локализация" %>
|
||||||
|
<% field_select "ui_language" "Язык интерфейса" "$ui_locales" %>
|
||||||
|
<%# field_file "ui_locale_file" "Локальный файл" %>
|
||||||
|
<% button_submit %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
page_title="Обновление веб-интерфейса"
|
||||||
|
c="/usr/sbin/updatewebui.sh"
|
||||||
|
reboot="true"
|
||||||
|
[ "true" = "$POST_web_enforce" ] && c="${c} -f"
|
||||||
|
[ "true" = "$POST_web_verbose" ] && c="${c} -v"
|
||||||
|
[ "true" = "$POST_web_noreboot" ] && reboot="false"
|
||||||
|
if [ -n "$POST_web_branch" ]; then
|
||||||
|
c="${c} -b $POST_web_branch"
|
||||||
|
elif [ -n "$POST_web_commit" ]; then
|
||||||
|
c="${c} -c $POST_web_commit"
|
||||||
|
fi
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
<h3 class="alert alert-warning">НЕ ЗАКРЫВАЙТЕ, НЕ ОБНОВЛЯЙТЕ И НЕ УХОДИТЕ С ЭТОЙ СТРАНИЦЫ, ПОКА ПРОЦЕСС НЕ ЗАВЕРШЕН!</h3>
|
||||||
|
<h5># <%= $c %></h5>
|
||||||
|
<pre id="output" data-cmd="<%= $c %>" data-reboot="<%= $reboot %>"></pre>
|
||||||
|
<%in p/footer.cgi %>
|
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/haserl
|
||||||
|
<%in p/common.cgi %>
|
||||||
|
<%
|
||||||
|
if [ "POST" = "$REQUEST_METHOD" ]; then
|
||||||
|
case "$POST_action" in
|
||||||
|
init)
|
||||||
|
update_caminfo
|
||||||
|
redirect_back
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
redirect_to $SCRIPT_NAME "danger" "UNKNOWN ACTION: $POST_action"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
page_title="Веб интерфейс"
|
||||||
|
|
||||||
|
web_branch="master"
|
||||||
|
[ -n "$ui_version" ] && web_branch="$(echo "$ui_version" | cut -d+ -f1)"
|
||||||
|
%>
|
||||||
|
<%in p/header.cgi %>
|
||||||
|
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<h3>Версия прошивки</h3>
|
||||||
|
<dl class="list small">
|
||||||
|
<dt>Установленная</dt><dd><%= $ui_version %></dd>
|
||||||
|
<dt>Стабильная</dt><dd id="microbe-web-master-ver"></dd>
|
||||||
|
<dt>Нестабильная</dt><dd id="microbe-web-dev-ver"></dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>Обновление</h3>
|
||||||
|
<% if [ -n "$network_gateway" ]; then %>
|
||||||
|
<form action="webui-update.cgi" method="post">
|
||||||
|
<% field_hidden "action" "update" %>
|
||||||
|
<% field_select "web_branch" "Тип прошивки" "master:Стабильная,dev:Тестовая" %>
|
||||||
|
<% if [ "$debug" -gt 0 ]; then %>
|
||||||
|
<% field_text "web_commit" "Commit" "" %>
|
||||||
|
<% fi %>
|
||||||
|
<% field_checkbox "web_verbose" "Подробный вывод." %>
|
||||||
|
<% field_checkbox "web_enforce" "Установить, даже если та же версия." %>
|
||||||
|
<% field_checkbox "web_noreboot" "Не перезагружать после обновления." %>
|
||||||
|
<% button_submit "Установить обновление с GitHub" "warning" %>
|
||||||
|
</form>
|
||||||
|
<% else %>
|
||||||
|
<p class="alert alert-danger">Для обновления требуется доступ к GitHub.</p>
|
||||||
|
<% fi %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const GH_URL="https://github.com/OpenIPC/";
|
||||||
|
const GH_API="https://api.github.com/repos/OpenIPC/";
|
||||||
|
|
||||||
|
function checkUpdates() {
|
||||||
|
queryBranch('microbe-web', 'master');
|
||||||
|
queryBranch('microbe-web', 'dev');
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryBranch(repo, branch) {
|
||||||
|
var oReq = new XMLHttpRequest();
|
||||||
|
oReq.addEventListener("load", function(){
|
||||||
|
const d = JSON.parse(this.response);
|
||||||
|
const sha_short = d.commit.sha.slice(0,7);
|
||||||
|
const date = d.commit.commit.author.date.slice(0,10);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = GH_URL + repo + '/commits/' + branch;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.textContent = branch + '+' + sha_short + ', ' + date;
|
||||||
|
const el = $('#' + repo + '-' + branch + '-ver').appendChild(link);
|
||||||
|
});
|
||||||
|
oReq.open("GET", GH_API + repo + '/branches/' + branch);
|
||||||
|
oReq.setRequestHeader("Authorization", "Basic " + btoa("<%= "${GITHUB_USERNAME}:${GITHUB_TOKEN}" %>"));
|
||||||
|
oReq.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', checkUpdates);
|
||||||
|
</script>
|
||||||
|
<%in p/footer.cgi %>
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta content="0;url=/cgi-bin/preview.cgi" http-equiv="refresh">
|
||||||
|
<meta content="no-store" name="cache-control">
|
||||||
|
<title>Мелдана</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
location.href = "http://" + location.host + ":85/";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Пожалуйста, откройте веб-интерфейс на порту 85.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta content="width=device-width,initial-scale=1" name="viewport">
|
||||||
|
<title>Пожалуйста подождите.... Идёт загрузка</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 10vw;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 5vw;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<h1>Мелдана</h1>
|
||||||
|
<h3>Перезагрузка... Пожалуйста подождите...</h3>
|
||||||
|
<progress max="15" value="0"></progress>
|
||||||
|
</main>
|
||||||
|
<script>
|
||||||
|
const u = window.location.protocol + '//' + window.location.host;
|
||||||
|
const p = document.querySelector('progress');
|
||||||
|
let s = 0;
|
||||||
|
|
||||||
|
function t() {
|
||||||
|
s += 1;
|
||||||
|
p.value = s;
|
||||||
|
(s === p.max) ? g() : setTimeout(t, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function g() {
|
||||||
|
(async () => {
|
||||||
|
await fetch(u, {method: 'HEAD', mode: 'no-cors'}).then(() => {
|
||||||
|
window.location.replace(u);
|
||||||
|
}).catch(() => {
|
||||||
|
s = 0;
|
||||||
|
setTimeout(t, 1000);
|
||||||
|
})
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(t, 1000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,7 @@
|
||||||
|
config BR2_PACKAGE_MICROBE_WEB
|
||||||
|
bool "microbe-web"
|
||||||
|
help
|
||||||
|
The simplest web interface constructor based on
|
||||||
|
httpd and haserl.
|
||||||
|
|
||||||
|
https://openipc.org
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DAEMON="httpd"
|
||||||
|
PIDFILE="/var/run/$DAEMON.pid"
|
||||||
|
CONFFILE="/etc/httpd.conf"
|
||||||
|
|
||||||
|
HTTPD_ARGS="httpd -p 85 -f -c $CONFFILE -r Authentication"
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
|
||||||
|
|
||||||
|
if [ "$(fw_printenv -n debug)" ]; then
|
||||||
|
echo "Development mode"
|
||||||
|
sed -i "/^\/cgi-bin:admin:/s/^/#/" $CONFFILE
|
||||||
|
else
|
||||||
|
echo "Production mode"
|
||||||
|
sed -i "/^#\/cgi-bin:admin:/s/^#//" $CONFFILE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The httpd does not create a pidfile, so pass "-n" in the command line
|
||||||
|
# and use "-m" to instruct start-stop-daemon to create one.
|
||||||
|
start() {
|
||||||
|
printf 'Starting %s: ' "$DAEMON"
|
||||||
|
[ -f /usr/sbin/$DAEMON ] || echo -en "DISABLED, "
|
||||||
|
# shellcheck disable=SC2086 # we need the word splitting
|
||||||
|
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/usr/sbin/$DAEMON" \
|
||||||
|
-- $HTTPD_ARGS
|
||||||
|
status=$?
|
||||||
|
if [ "$status" -eq 0 ]; then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "FAIL"
|
||||||
|
fi
|
||||||
|
return "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
printf 'Stopping %s: ' "$DAEMON"
|
||||||
|
[ -f /usr/sbin/$DAEMON ] || echo -en "DISABLED, "
|
||||||
|
start-stop-daemon -K -q -p "$PIDFILE"
|
||||||
|
status=$?
|
||||||
|
if [ "$status" -eq 0 ]; then
|
||||||
|
rm -f "$PIDFILE"
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "FAIL"
|
||||||
|
fi
|
||||||
|
return "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
stop
|
||||||
|
sleep 1
|
||||||
|
start
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start|stop|restart)
|
||||||
|
"$1";;
|
||||||
|
reload)
|
||||||
|
# Restart, since there is no true "reload" feature.
|
||||||
|
restart;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart|reload}"
|
||||||
|
exit 1
|
||||||
|
esac
|
|
@ -0,0 +1,8 @@
|
||||||
|
#
|
||||||
|
H:/var/www
|
||||||
|
A:127.0.0.1
|
||||||
|
A:*
|
||||||
|
D:8.8.8.8/32
|
||||||
|
E401:401.html
|
||||||
|
/cgi-bin:root:*
|
||||||
|
#
|
|
@ -0,0 +1,29 @@
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# microbe-web
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
MICROBE_WEB_SITE_METHOD = git
|
||||||
|
MICROBE_WEB_SITE = https://github.com/openipc/microbe-web
|
||||||
|
MICROBE_WEB_VERSION = bbb49c57695c116a17219d0898dc11cc696261df
|
||||||
|
|
||||||
|
MICROBE_WEB_LICENSE = MIT
|
||||||
|
MICROBE_WEB_LICENSE_FILES = LICENSE
|
||||||
|
|
||||||
|
define MICROBE_WEB_INSTALL_TARGET_CMDS
|
||||||
|
$(INSTALL) -m 755 -d $(TARGET_DIR)/etc
|
||||||
|
cp $(MICROBE_WEB_PKGDIR)/files/httpd.conf $(TARGET_DIR)/etc
|
||||||
|
|
||||||
|
$(INSTALL) -m 755 -d $(TARGET_DIR)/etc/init.d
|
||||||
|
cp $(MICROBE_WEB_PKGDIR)/files/S50httpd $(TARGET_DIR)/etc/init.d
|
||||||
|
cp -rv $(@D)/files/etc/init.d/* $(TARGET_DIR)/etc/init.d
|
||||||
|
|
||||||
|
$(INSTALL) -m 755 -d $(TARGET_DIR)/usr
|
||||||
|
cp -rv $(@D)/files/usr/sbin $(TARGET_DIR)/usr
|
||||||
|
|
||||||
|
$(INSTALL) -m 755 -d $(TARGET_DIR)/var
|
||||||
|
cp -rv $(@D)/files/var/www $(TARGET_DIR)/var
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(generic-package))
|
Loading…
Reference in New Issue