init
This commit is contained in:
80
cgi-bin/ext-openwall.cgi
Executable file
80
cgi-bin/ext-openwall.cgi
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="OpenWall"
|
||||
config_file=/etc/webui/openwall.conf
|
||||
params="enabled crontab caption interval heif proxy"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
for p in $params; do
|
||||
eval openwall_${p}=\$POST_openwall_${p}
|
||||
done
|
||||
|
||||
if [ "$openwall_enabled" = "true" ]; then
|
||||
[ "$openwall_interval" -lt "15" ] && set_error_flag "Keep interval at 15 minutes or longer."
|
||||
fi
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
rm -f "$config_file"
|
||||
for p in $params; do
|
||||
echo "openwall_${p}=\"$(eval echo \$openwall_${p})\"" >> "$config_file"
|
||||
done
|
||||
|
||||
sed -i /openwall/d /etc/crontabs/root
|
||||
if [ "$openwall_enabled" = "true" ] && [ "$openwall_crontab" = "true" ]; then
|
||||
echo "*/${openwall_interval} * * * * /usr/sbin/openwall" >> /etc/crontabs/root
|
||||
fi
|
||||
|
||||
redirect_back "success" "OpenWall config updated."
|
||||
fi
|
||||
|
||||
redirect_to "$SCRIPT_NAME"
|
||||
fi
|
||||
|
||||
[ -e "$config_file" ] && include $config_file
|
||||
[ -z "$openwall_crontab" ] && openwall_crontab="true"
|
||||
[ -z "$openwall_interval" ] && openwall_interval="15"
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p>This extension allows you to share images from your OpenIPC camera on the <a href="https://openipc.org/open-wall">Open Wall</a>
|
||||
page of our website. The images you share will allow us to determine the quality of images from different cameras.
|
||||
We also collect your MAC address, chipset, sensor, flashsize, firmware version, and uptime.</p>
|
||||
</div>
|
||||
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_switch "openwall_enabled" "Enable OpenWall" "eval" %>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<% field_string "openwall_interval" "Interval" "eval" "15 30 60 120" "Minutes between submissions." %>
|
||||
<% field_text "openwall_caption" "Caption" "Location or short description." %>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<% field_switch "openwall_crontab" "Add to Crontab" "eval" "Send pictures timed by interval." %>
|
||||
<% field_switch "openwall_heif" "Use HEIF format" "eval" "Requires H265 codec on Video0." %>
|
||||
<% field_switch "openwall_proxy" "Use SOCKS5" "eval" "<a href=\"ext-proxy.cgi\">Configure proxy access.</a>" %>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<% [ -e "$config_file" ] && ex "cat $config_file" %>
|
||||
<% ex "grep openwall /etc/crontabs/root" %>
|
||||
</div>
|
||||
</div>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
<% if [ "$openwall_crontab" = "true" ]; then %>
|
||||
$('#openwall_crontab').checked = true;
|
||||
<% fi %>
|
||||
|
||||
<% if [ "$(yaml-cli -g .video0.codec)" != "h265" ]; then %>
|
||||
$('#openwall_heif').checked = false;
|
||||
$('#openwall_heif').disabled = true;
|
||||
<% fi %>
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
39
cgi-bin/ext-proxy.cgi
Executable file
39
cgi-bin/ext-proxy.cgi
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Proxy"
|
||||
config_file=/etc/webui/proxy.conf
|
||||
params="host port username password"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
rm -f "$config_file"
|
||||
for p in $params; do
|
||||
echo "socks5_${p}=\"$(eval echo \$POST_socks5_${p})\"" >> "$config_file"
|
||||
done
|
||||
|
||||
redirect_to "$SCRIPT_NAME"
|
||||
fi
|
||||
|
||||
[ -e "$config_file" ] && 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 host" %>
|
||||
<% field_text "socks5_port" "SOCKS5 port" "1080" %>
|
||||
<% field_text "socks5_username" "SOCKS5 username" %>
|
||||
<% field_password "socks5_password" "SOCKS5 password" %>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<% [ -e "$config_file" ] && ex "cat $config_file" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
78
cgi-bin/ext-telegram.cgi
Executable file
78
cgi-bin/ext-telegram.cgi
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Telegram"
|
||||
config_file=/etc/webui/telegram.conf
|
||||
params="enabled token channel interval caption crontab document heif proxy"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
for p in $params; do
|
||||
eval telegram_${p}=\$POST_telegram_${p}
|
||||
done
|
||||
|
||||
if [ "$telegram_enabled" = "true" ]; then
|
||||
[ -z "$telegram_token" ] && set_error_flag "Telegram token cannot be empty."
|
||||
[ -z "$telegram_channel" ] && set_error_flag "Telegram channel cannot be empty."
|
||||
fi
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
rm -f "$config_file"
|
||||
for p in $params; do
|
||||
echo "telegram_${p}=\"$(eval echo \$telegram_${p})\"" >> "$config_file"
|
||||
done
|
||||
|
||||
sed -i /telegram/d /etc/crontabs/root
|
||||
if [ "$telegram_enabled" = "true" ] && [ "$telegram_crontab" = "true" ]; then
|
||||
echo "*/${telegram_interval} * * * * /usr/sbin/telegram" >> /etc/crontabs/root
|
||||
fi
|
||||
|
||||
redirect_back "success" "Telegram config updated."
|
||||
fi
|
||||
|
||||
redirect_to "$SCRIPT_NAME"
|
||||
fi
|
||||
|
||||
[ -e "$config_file" ] && include $config_file
|
||||
[ -z "$telegram_crontab" ] && telegram_crontab="true"
|
||||
[ -z "$telegram_interval" ] && telegram_interval="15"
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_switch "telegram_enabled" "Enable Telegram" "eval" %>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<% field_text "telegram_token" "Token" "Telegram bot authentication token." %>
|
||||
<% field_text "telegram_channel" "Channel" "Channel to post the images to." %>
|
||||
<% field_string "telegram_interval" "Interval" "eval" "15 30 60 120" "Minutes between submissions." %>
|
||||
<% field_text "telegram_caption" "Caption" "Location or short description." %>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<% field_switch "telegram_crontab" "Add to Crontab" "eval" "Send pictures timed by interval." %>
|
||||
<% field_switch "telegram_document" "Send as document" "eval" "Attach picture as general file." %>
|
||||
<% field_switch "telegram_heif" "Use HEIF format" "eval" "Requires H265 codec on Video0." %>
|
||||
<% field_switch "telegram_proxy" "Use SOCKS5" "eval" "<a href=\"ext-proxy.cgi\">Configure proxy access.</a>" %>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<% [ -e "$config_file" ] && ex "cat $config_file" %>
|
||||
<% ex "grep telegram /etc/crontabs/root" %>
|
||||
</div>
|
||||
</div>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
<% if [ "$telegram_crontab" = "true" ]; then %>
|
||||
$('#telegram_crontab').checked = true;
|
||||
<% fi %>
|
||||
|
||||
<% if [ "$(yaml-cli -g .video0.codec)" != "h265" ]; then %>
|
||||
$('#telegram_heif').checked = false;
|
||||
$('#telegram_heif').disabled = true;
|
||||
<% fi %>
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
66
cgi-bin/ext-tunnel.cgi
Executable file
66
cgi-bin/ext-tunnel.cgi
Executable file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Tunnel"
|
||||
conf_file=/tmp/vtund.conf
|
||||
env_host=$(fw_printenv -n vtun)
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
if [ "$POST_action" = "reset" ]; then
|
||||
killall -q tunnel
|
||||
killall -q vtund
|
||||
rm -f "$conf_file"
|
||||
fw_setenv vtun
|
||||
sleep 1
|
||||
redirect_to "$SCRIPT_NAME" "danger" "Tunnel is down"
|
||||
fi
|
||||
|
||||
if [ -n "$POST_vtun_host" ]; then
|
||||
fw_setenv vtun "$POST_vtun_host"
|
||||
/etc/init.d/S98vtun start
|
||||
sleep 1
|
||||
redirect_to "$SCRIPT_NAME" "success" "Tunnel is up"
|
||||
fi
|
||||
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">
|
||||
<% if [ -e "$conf_file" ]; then %>
|
||||
<div class="alert alert-success">
|
||||
<h4>Virtual Tunnel is up</h4>
|
||||
<p>Use the following credentials to set up remote access via virtual tunnel:</p>
|
||||
<dl class="mb-0">
|
||||
<dt>Tunnel ID</dt>
|
||||
<dd><%= ${network_macaddr//:/} | tr a-z A-Z %></dd>
|
||||
<dt>Password</dt>
|
||||
<dd><% grep password $conf_file | xargs | cut -d' ' -f2 | sed 's/;$//' %>
|
||||
</dl>
|
||||
</div>
|
||||
<% fi %>
|
||||
|
||||
<h3>Settings</h3>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% if [ -n "$env_host" ]; then %>
|
||||
<% field_hidden "action" "reset" %>
|
||||
<% button_submit "Reset configuration" %>
|
||||
<% else %>
|
||||
<% field_text "vtun_host" "Virtual Tunnel address" %>
|
||||
<% button_submit %>
|
||||
<% fi %>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col col-lg-8">
|
||||
<h3>Configuration</h3>
|
||||
<%
|
||||
[ -e "$conf_file" ] && ex "cat $conf_file"
|
||||
[ -n "$env_host" ] && ex "fw_printenv | grep vtun"
|
||||
ex "pgrep -a vtund"
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
52
cgi-bin/fw-editor.cgi
Executable file
52
cgi-bin/fw-editor.cgi
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Text Editor"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
editor_file="$POST_editor_file"
|
||||
editor_text="$POST_editor_text"
|
||||
|
||||
# strip carriage return (\u000D) characters
|
||||
editor_text=$(echo "$editor_text" | sed s/\\r//g)
|
||||
|
||||
case "$POST_action" in
|
||||
save)
|
||||
if [ -z "$editor_text" ]; then
|
||||
log_create "warning" "Empty payload. File not saved!"
|
||||
else
|
||||
[ -f "${editor_file}.backup" ] && rm "${editor_file}.backup"
|
||||
echo "$editor_text" > "$editor_file"
|
||||
redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "File saved."
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
log_create "danger" "UNKNOWN ACTION: $POST_action"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
editor_file="$GET_f"
|
||||
if [ ! -f "$editor_file" ]; then
|
||||
log_create "danger" "File not found!"
|
||||
elif [ -n "$editor_file" ]; then
|
||||
if [ "b" = "$( (cat -v "$editor_file" | grep -q "\^@") && echo "b" )" ]; then
|
||||
log_create "danger" "Not a text file!"
|
||||
elif [ "$(stat -c%s $editor_file)" -gt "102400" ]; then
|
||||
log_create "danger" "Uploaded file is too large!"
|
||||
else
|
||||
editor_text="$(cat $editor_file)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "action" "save" %>
|
||||
<% field_hidden "editor_file" "$editor_file" %>
|
||||
<% field_textedit "editor_text" "File content" "$editor_file" %>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
68
cgi-bin/fw-interface.cgi
Executable file
68
cgi-bin/fw-interface.cgi
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/haserl --upload-limit=100 --upload-dir=/tmp
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Interface Settings"
|
||||
config_file="/etc/webui/webui.conf"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
case "$POST_action" in
|
||||
access)
|
||||
password_default="$POST_password_default"
|
||||
if [ -z "$password_default" ]; then
|
||||
redirect_to "$SCRIPT_NAME" "danger" "Password cannot be empty!"
|
||||
fi
|
||||
|
||||
password_confirm="$POST_password_confirm"
|
||||
if [ "$password_default" != "$password_confirm" ]; then
|
||||
redirect_to "$SCRIPT_NAME" "danger" "Password does not match!"
|
||||
fi
|
||||
|
||||
echo "root:${password_default}" | chpasswd
|
||||
update_caminfo
|
||||
redirect_to "/" "success" "Password updated."
|
||||
;;
|
||||
|
||||
theme)
|
||||
eval webui_theme=\$POST_webui_theme
|
||||
echo webui_theme=\"$webui_theme\" > $config_file
|
||||
update_caminfo
|
||||
redirect_back "success" "Settings updated."
|
||||
;;
|
||||
|
||||
*)
|
||||
redirect_to "$SCRIPT_NAME" "danger" "UNKNOWN ACTION: $POST_action"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
ui_username="$USER"
|
||||
%>
|
||||
|
||||
<%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>Access</h3>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "action" "access" %>
|
||||
<p class="string">
|
||||
<label for="ui_username" class="form-label">Username</label>
|
||||
<input type="text" id="ui_username" name="ui_username" value="<%= $ui_username %>" class="form-control" autocomplete="username" disabled>
|
||||
</p>
|
||||
<% field_password "password_default" "Password" %>
|
||||
<% field_password "password_confirm" "Confirm Password" %>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Theme</h3>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "action" "theme" %>
|
||||
<% field_string "webui_theme" "Theme" "eval" "dark light" %>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
153
cgi-bin/fw-network.cgi
Executable file
153
cgi-bin/fw-network.cgi
Executable file
@ -0,0 +1,153 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
|
||||
<%
|
||||
page_title="Network Settings"
|
||||
params="address dhcp gateway hostname nameserver netmask interface wlan_ssid wlan_password"
|
||||
|
||||
network_list="$(ls /sys/class/net | grep -e eth0 -e wlan0)"
|
||||
network_nameserver="$(cat /etc/resolv.conf | grep nameserver | cut -d' ' -f2)"
|
||||
network_netmask="$(ifconfig ${network_interface} | grep Mask | cut -d: -f4)"
|
||||
network_dhcp="$(cat /etc/network/interfaces.d/${network_interface} | grep -q dhcp && echo true)"
|
||||
|
||||
network_wlan_ssid="$(fw_printenv -n wlanssid)"
|
||||
network_wlan_password="$(fw_printenv -n wlanpass)"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; 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
|
||||
touch /tmp/system-reboot
|
||||
redirect_back "success" "MAC address updated."
|
||||
else
|
||||
if [ -z "$POST_mac_address" ]; then
|
||||
redirect_back "warning" "Empty MAC address."
|
||||
else
|
||||
redirect_back "warning" "Invalid MAC address: ${POST_mac_address}"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
reset)
|
||||
rm -f /etc/network/interfaces.d/*
|
||||
cp -f /rom/etc/network/interfaces.d/* /etc/network/interfaces.d
|
||||
redirect_back
|
||||
;;
|
||||
|
||||
update)
|
||||
for p in $params; do
|
||||
eval network_${p}=\$POST_network_${p}
|
||||
done
|
||||
|
||||
[ -z "$network_interface" ] && set_error_flag "Default network interface cannot be empty."
|
||||
if [ "$network_interface" = "wlan0" ]; then
|
||||
[ -z "$network_wlan_ssid" ] && set_error_flag"WLAN SSID cannot be empty."
|
||||
[ -z "$network_wlan_password" ] && set_error_flag "WLAN Password cannot be empty."
|
||||
fi
|
||||
|
||||
if [ "$network_dhcp" = "false" ]; then
|
||||
network_mode="static"
|
||||
[ -z "$network_address" ] && set_error_flag "IP address cannot be empty."
|
||||
[ -z "$network_netmask" ] && set_error_flag "Networking mask cannot be empty."
|
||||
else
|
||||
network_mode="dhcp"
|
||||
fi
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
command="setnetwork"
|
||||
command="${command} -i $network_interface"
|
||||
command="${command} -m $network_mode"
|
||||
command="${command} -h $network_hostname"
|
||||
|
||||
if [ "$network_interface" = "wlan0" ]; then
|
||||
command="${command} -s $network_wlan_ssid"
|
||||
command="${command} -p $network_wlan_password"
|
||||
fi
|
||||
|
||||
if [ "$network_mode" != "dhcp" ]; then
|
||||
command="${command} -a $network_address"
|
||||
command="${command} -n $network_netmask"
|
||||
[ -n "$network_gateway" ] && command="${command} -g $network_gateway"
|
||||
[ -n "$network_nameserver" ] && command="${command} -d $network_nameserver"
|
||||
fi
|
||||
|
||||
echo "$command" >> /tmp/webui.log
|
||||
eval "$command" > /dev/null 2>&1
|
||||
|
||||
update_caminfo
|
||||
redirect_back "success" "Network settings updated."
|
||||
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" "update" %>
|
||||
<% field_text "network_hostname" "Hostname" %>
|
||||
<% field_string "network_interface" "Network interface" "eval" "$network_list" %>
|
||||
<% field_text "network_wlan_ssid" "WLAN SSID" %>
|
||||
<% field_text "network_wlan_password" "WLAN Password" %>
|
||||
|
||||
<% field_switch "network_dhcp" "Use DHCP" "eval" %>
|
||||
<% field_text "network_address" "IP Address" %>
|
||||
<% field_text "network_netmask" "IP Netmask" %>
|
||||
<% field_text "network_gateway" "Gateway" %>
|
||||
<% field_text "network_nameserver" "DNS" %>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-danger mt-4">
|
||||
<h5>Reset network configuration</h5>
|
||||
<p>Restore the config file bundled with firmware. All changes to the default configuration will be lost!</p>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "action" "reset" %>
|
||||
<% button_submit "Reset config" "danger" %>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col col-md-6 col-lg-8">
|
||||
<% for dev in $network_list; do %>
|
||||
<% ex "cat /etc/network/interfaces.d/$dev" %>
|
||||
<% done %>
|
||||
<% if [ -n "$(fw_printenv -n wlandev)" ]; then %>
|
||||
<% ex "fw_printenv | grep wlan" %>
|
||||
<% fi %>
|
||||
<% ex "ifconfig" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleStatic() {
|
||||
const c = $('#network_dhcp').checked;
|
||||
const ids = ['network_address','network_netmask','network_gateway','network_nameserver'];
|
||||
ids.forEach(id => {
|
||||
$('#' + id).disabled = c;
|
||||
let el = $('#' + id + '_wrap');
|
||||
c ? el.classList.add('d-none') : el.classList.remove('d-none');
|
||||
});
|
||||
}
|
||||
|
||||
function toggleInterface() {
|
||||
const ids = ['network_wlan_ssid','network_wlan_password'];
|
||||
if ($('#network_interface').value == 'wlan0') {
|
||||
ids.forEach(id => $('#' + id + '_wrap').classList.remove('d-none'));
|
||||
} else {
|
||||
ids.forEach(id => $('#' + id + '_wrap').classList.add('d-none'));
|
||||
}
|
||||
}
|
||||
|
||||
$('#network_interface').addEventListener('change', toggleInterface);
|
||||
$('#network_dhcp').addEventListener('change', toggleStatic);
|
||||
|
||||
toggleInterface();
|
||||
toggleStatic();
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
17
cgi-bin/fw-reset.cgi
Executable file
17
cgi-bin/fw-reset.cgi
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Erasing Overlay"
|
||||
c="/usr/sbin/sysupgrade -s -n -x"
|
||||
r="true"
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<h3 class="alert alert-warning">DO NOT CLOSE, REFRESH, OR NAVIGATE AWAY FROM THIS PAGE UNTIL THE PROCESS IS FINISHED!</h3>
|
||||
<pre id="output" data-cmd="<%= $c %>" data-reboot="<%= $r %>"></pre>
|
||||
|
||||
<script>
|
||||
const el = $('pre#output');
|
||||
runCmd("cmd")
|
||||
</script>
|
||||
<%in p/footer.cgi %>
|
||||
76
cgi-bin/fw-restart.cgi
Executable file
76
cgi-bin/fw-restart.cgi
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/haserl
|
||||
Content-type: text/html; charset=UTF-8
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="<%= ${webui_theme:=dark} %>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Restart - OpenIPC</title>
|
||||
<link href="/a/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
padding: 1vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 6vw;
|
||||
line-height: 1.5;
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
h1 span {
|
||||
color:#f80
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2vw;
|
||||
line-height: 1;
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
progress {
|
||||
width: 30rem;
|
||||
max-width: 90%;
|
||||
margin-top: 5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<h1>OpenIPC</h1>
|
||||
<h3>Restarting. Please wait...</h3>
|
||||
<progress max="20" 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);
|
||||
<% reboot -d1 %>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
16
cgi-bin/fw-restore.cgi
Executable file
16
cgi-bin/fw-restore.cgi
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
[ -z "$GET_f" ] && set_error_flag "Nothing to restore."
|
||||
|
||||
file=$GET_f
|
||||
[ ! -f "/rom/${file}" ] && set_error_flag "File /rom/${file} not found!"
|
||||
[ -n "$error" ] && redirect_back
|
||||
|
||||
cp "/rom/${file}" "${file}"
|
||||
if [ $? -eq 0 ]; then
|
||||
redirect_back "success" "File ${file} restored to firmware defaults."
|
||||
else
|
||||
redirect_back "danger" "Cannot restore ${file}!"
|
||||
fi
|
||||
%>
|
||||
23
cgi-bin/fw-settings.cgi
Executable file
23
cgi-bin/fw-settings.cgi
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Firmware Settings" %>
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<div class="row row-cols-md-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="alert alert-danger">
|
||||
<h4>Restart Camera</h4>
|
||||
<p>Reboot camera to apply new settings and reset temporary files.</p>
|
||||
<a class="btn btn-danger" href="fw-restart.cgi">Restart Camera</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="alert alert-danger">
|
||||
<h4>Reset Firmware</h4>
|
||||
<p>Revert firmware to original state by resetting the overlay partition.</p>
|
||||
<a class="btn btn-danger" href="fw-reset.cgi">Reset Firmware</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
21
cgi-bin/fw-system.cgi
Executable file
21
cgi-bin/fw-system.cgi
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="System Upgrade"
|
||||
c="/usr/sbin/sysupgrade -s"
|
||||
[ "$POST_fw_kernel" = "true" ] && c="${c} -k"
|
||||
[ "$POST_fw_rootfs" = "true" ] && c="${c} -r"
|
||||
[ "$POST_fw_reboot" != "true" ] && c="${c} -x"
|
||||
[ "$POST_fw_reset" = "true" ] && c="${c} -n"
|
||||
[ "$POST_fw_force" = "true" ] && c="${c} --force_ver"
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<h3 class="alert alert-warning">DO NOT CLOSE, REFRESH, OR NAVIGATE AWAY FROM THIS PAGE UNTIL THE PROCESS IS FINISHED!</h3>
|
||||
<pre id="output" data-cmd="<%= $c %>"></pre>
|
||||
|
||||
<script>
|
||||
const el = $('pre#output');
|
||||
runCmd("cmd")
|
||||
</script>
|
||||
<%in p/footer.cgi %>
|
||||
131
cgi-bin/fw-time.cgi
Executable file
131
cgi-bin/fw-time.cgi
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Time Settings"
|
||||
tz_data=$(cat /etc/TZ)
|
||||
tz_name=$(cat /etc/timezone)
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
case "$POST_action" in
|
||||
update)
|
||||
[ -z "$POST_tz_name" ] && redirect_to "$SCRIPT_NAME" "warning" "Empty timezone name. Skipping."
|
||||
[ -z "$POST_tz_data" ] && redirect_to "$SCRIPT_NAME" "warning" "Empty timezone value. Skipping."
|
||||
[ "$tz_data" != "$POST_tz_data" ] && echo "${POST_tz_data}" > /etc/TZ
|
||||
[ "$tz_name" != "$POST_tz_name" ] && echo "${POST_tz_name}" > /etc/timezone
|
||||
|
||||
rm -f /etc/ntp.conf
|
||||
for i in $(seq 0 3); do
|
||||
eval ntp="\$POST_server_${i}"
|
||||
[ -n "$ntp" ] && echo "server $ntp iburst" >> /etc/ntp.conf
|
||||
done
|
||||
redirect_back "success" "Configuration updated."
|
||||
;;
|
||||
esac
|
||||
|
||||
update_caminfo
|
||||
redirect_to "$SCRIPT_NAME" "success" "Timezone updated."
|
||||
fi
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "action" "update" %>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<h3>Time Zone</h3>
|
||||
<datalist id="tz_list"></datalist>
|
||||
<p class="string">
|
||||
<label for="tz_name" class="form-label">Zone name</label>
|
||||
<input type="text" id="tz_name" name="tz_name" value="<%= $tz_name %>" class="form-control" list="tz_list">
|
||||
<span class="hint text-secondary">Type the name of the nearest large city.</span>
|
||||
</p>
|
||||
<p class="string">
|
||||
<label for="tz_data" class="form-label">Zone string</label>
|
||||
<input type="text" id="tz_data" name="tz_data" value="<%= $tz_data %>" class="form-control" readonly>
|
||||
<span class="hint text-secondary">Control string of the timezone selected above.</span>
|
||||
</p>
|
||||
<p><a href="#" id="frombrowser">Pick up timezone from browser</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Synchronization</h3>
|
||||
<%
|
||||
for i in $(seq 0 3); do
|
||||
eval server_${i}=$(sed -n $((i + 1))p /etc/ntp.conf | awk '{print $2}')
|
||||
field_text "server_${i}" "Server $((i + 1))"
|
||||
done
|
||||
%>
|
||||
<p id="sync-time-wrapper"><a href="#" id="sync-time">Sync time</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Configuration</h3>
|
||||
<% ex "cat /etc/timezone" %>
|
||||
<% ex "cat /etc/TZ" %>
|
||||
<% ex "cat /etc/ntp.conf" %>
|
||||
</div>
|
||||
</div>
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<script src="/a/timezone.js"></script>
|
||||
<script>
|
||||
function findTimezone(tz) {
|
||||
return tz.n == $("#tz_name").value;
|
||||
}
|
||||
|
||||
function updateTimezone() {
|
||||
const tz = TZ.filter(findTimezone);
|
||||
$("#tz_data").value = (tz.length == 0) ? "" : tz[0].v;
|
||||
}
|
||||
|
||||
function useBrowserTimezone(event) {
|
||||
event.preventDefault();
|
||||
$("#tz_name").value = Intl.DateTimeFormat().resolvedOptions().timeZone.replaceAll('_', ' ');
|
||||
updateTimezone();
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const tzn = $("#tz_name");
|
||||
if (navigator.userAgent.includes("Android") && navigator.userAgent.includes("Firefox")) {
|
||||
const sel = document.createElement("select");
|
||||
sel.classList.add("form-select");
|
||||
sel.name = "tz_name";
|
||||
sel.id = "tz_name";
|
||||
sel.options.add(new Option());
|
||||
let opt;
|
||||
TZ.forEach(function (tz) {
|
||||
opt = new Option(tz.n);
|
||||
opt.selected = (tz.n == tzn.value);
|
||||
sel.options.add(opt);
|
||||
});
|
||||
tzn.replaceWith(sel);
|
||||
} else {
|
||||
const el = $("#tz_list");
|
||||
el.innerHTML = "";
|
||||
TZ.forEach(function (tz) {
|
||||
const o = document.createElement("option");
|
||||
o.value = tz.n;
|
||||
el.appendChild(o);
|
||||
});
|
||||
}
|
||||
tzn.addEventListener("focus", ev => ev.target.select());
|
||||
tzn.addEventListener("selectionchange", updateTimezone);
|
||||
tzn.addEventListener("change", updateTimezone);
|
||||
$("#frombrowser").addEventListener("click", useBrowserTimezone);
|
||||
});
|
||||
|
||||
$('#sync-time').addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
fetch('/cgi-bin/j/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 %>
|
||||
56
cgi-bin/fw-update.cgi
Executable file
56
cgi-bin/fw-update.cgi
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Firmware Update"
|
||||
if [ -n "$network_gateway" ]; then
|
||||
fw_soc=$soc
|
||||
if [ "$soc_vendor" = "ingenic" ]; then
|
||||
fw_soc=$soc_family
|
||||
fi
|
||||
|
||||
builder=$(fw_printenv -n upgrade)
|
||||
url="https://github.com/openipc/firmware/releases/download/latest/openipc.${fw_soc}-${flash_type}-${fw_variant}.tgz"
|
||||
ver=$(curl -m5 -ILs "${builder:-$url}" | grep Last-Modified | cut -d' ' -f2-)
|
||||
fi
|
||||
|
||||
if [ -n "$ver" ]; then
|
||||
fw_date=$(date -D "%a, %d %b %Y %T GMT" +"2.4.%m.%d" --date "$ver")
|
||||
else
|
||||
fw_date="<span class=\"text-danger\">- no access to GitHub -</span>"
|
||||
fi
|
||||
|
||||
fw_kernel="true"
|
||||
fw_rootfs="true"
|
||||
fw_reboot="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>Version</h3>
|
||||
<dl class="list small">
|
||||
<dt>Installed</dt>
|
||||
<dd><%= $fw_version %></dd>
|
||||
<dt>On GitHub</dt>
|
||||
<dd id="firmware-master-ver"><%= $fw_date %></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Upgrade</h3>
|
||||
<% if [ -n "$ver" ]; then %>
|
||||
<form action="fw-system.cgi" method="post">
|
||||
<% field_switch "fw_kernel" "Upgrade kernel." "eval" %>
|
||||
<% field_switch "fw_rootfs" "Upgrade rootfs." "eval" %>
|
||||
<% field_switch "fw_reboot" "Restart after upgrade." "eval" %>
|
||||
<% field_switch "fw_reset" "Reset firmware." "eval" %>
|
||||
<% field_switch "fw_force" "Reflash installed version." "eval" %>
|
||||
<% button_submit "Install update from GitHub" "warning" %>
|
||||
</form>
|
||||
<% else %>
|
||||
<p class="alert alert-danger">Updating requires access to GitHub.</p>
|
||||
<% fi %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
6
cgi-bin/info-kernel.cgi
Executable file
6
cgi-bin/info-kernel.cgi
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Kernel Messages" %>
|
||||
<%in p/header.cgi %>
|
||||
<% ex "dmesg" %>
|
||||
<%in p/footer.cgi %>
|
||||
6
cgi-bin/info-majestic.cgi
Executable file
6
cgi-bin/info-majestic.cgi
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Majestic Messages" %>
|
||||
<%in p/header.cgi %>
|
||||
<% ex "logread | grep -o majestic.*" %>
|
||||
<%in p/footer.cgi %>
|
||||
13
cgi-bin/info-overlay.cgi
Executable file
13
cgi-bin/info-overlay.cgi
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
s=$(df | grep /overlay | xargs | cut -d' ' -f5)
|
||||
page_title="Overlay Partition"
|
||||
%>
|
||||
<%in p/header.cgi %>
|
||||
<div class="alert alert-primary">
|
||||
<h5>Overlay partition is <%= $s %> full.</h5>
|
||||
<% progressbar "${s/%/}" %>
|
||||
</div>
|
||||
<% ex "ls -Rl /overlay" %>
|
||||
<%in p/footer.cgi %>
|
||||
21
cgi-bin/j/locale.cgi
Executable file
21
cgi-bin/j/locale.cgi
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
mj_audio=Audio
|
||||
mj_cloud=Cloud
|
||||
mj_hls=HLS
|
||||
mj_image=Image
|
||||
mj_ipeye=IPEYE
|
||||
mj_isp=ISP
|
||||
mj_jpeg=JPEG
|
||||
mj_motionDetect=Motion
|
||||
mj_netip=NETIP
|
||||
mj_nightMode=Night
|
||||
mj_onvif=ONVIF
|
||||
mj_osd=OSD
|
||||
mj_outgoing=Outgoing
|
||||
mj_records=Record
|
||||
mj_rtsp=RTSP
|
||||
mj_system=System
|
||||
mj_video0=Video0
|
||||
mj_video1=Video1
|
||||
mj_watchdog=Watchdog
|
||||
mj_youtube=Youtube
|
||||
26
cgi-bin/j/pulse.cgi
Executable file
26
cgi-bin/j/pulse.cgi
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
web=$(pidof majestic)
|
||||
temp=$(ipcinfo -t 2> /dev/null)
|
||||
|
||||
if [ -n "$web" ]; then
|
||||
daynight_value=$(wget -q -T1 localhost/metrics/isp?value=isp_again -O -)
|
||||
fi
|
||||
|
||||
if [ -n "$temp" ]; then
|
||||
soc_temp="${temp%.*}°C"
|
||||
fi
|
||||
|
||||
mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
|
||||
mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo)
|
||||
mem_used=$(( 100 - (mem_free / (mem_total / 100)) ))
|
||||
overlay_used=$(df | grep /overlay | xargs | cut -d' ' -f5)
|
||||
uptime=$(awk '{m=$1/60; h=m/60; printf "%sd %sh %sm %ss\n", int(h/24), int(h%24), int(m%60), int($1%60) }' /proc/uptime)
|
||||
payload=$(printf '{"soc_temp":"%s","time_now":"%s","timezone":"%s","mem_used":"%d","overlay_used":"%d","daynight_value":"%d","uptime":"%s"}' \
|
||||
"${soc_temp}" "$(date +%s)" "$(cat /etc/timezone)" "${mem_used}" "${overlay_used//%/}" "${daynight_value:=-1}" "$uptime")
|
||||
|
||||
echo "HTTP/1.1 200 OK
|
||||
Content-type: application/json
|
||||
Pragma: no-cache
|
||||
|
||||
${payload}
|
||||
"
|
||||
24
cgi-bin/j/run.cgi
Executable file
24
cgi-bin/j/run.cgi
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
echo "HTTP/1.1 200 OK
|
||||
Content-type: text/html; charset=UTF-8
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
"
|
||||
|
||||
[ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g")
|
||||
[ -n "$cmd" ] && c=$(echo $cmd | base64 -d)
|
||||
[ -n "$web" ] && c=$(echo $web | base64 -d) && t="timeout 3"
|
||||
[ -z "$c" ] && echo "No command!" && exit 1
|
||||
|
||||
prompt() {
|
||||
echo "<b>$(whoami)@$(hostname):$PWD# ${1}</b>"
|
||||
}
|
||||
|
||||
export PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
cd /tmp || return
|
||||
|
||||
prompt "$c"
|
||||
eval "$t $c" 2>&1
|
||||
prompt
|
||||
|
||||
exit 0
|
||||
13
cgi-bin/j/time.cgi
Executable file
13
cgi-bin/j/time.cgi
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
if ntpd -n -q -N; then
|
||||
payload='{"result":"success","message":"Camera time synchronized with NTP server."}'
|
||||
else
|
||||
payload='{"result":"danger","message":"Synchronization failed!"}'
|
||||
fi
|
||||
|
||||
echo "HTTP/1.1 200 OK
|
||||
Content-type: application/json
|
||||
Pragma: no-cache
|
||||
|
||||
${payload}
|
||||
"
|
||||
20
cgi-bin/mj-configuration.cgi
Executable file
20
cgi-bin/mj-configuration.cgi
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Majestic Configuration" %>
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<div class="row row-cols-2">
|
||||
<% ex "cat $(get_config)" %>
|
||||
<div class="col">
|
||||
<%
|
||||
diff $(get_config /rom) $(get_config) > /tmp/majestic.patch
|
||||
ex "cat /tmp/majestic.patch"
|
||||
%>
|
||||
<div class="row">
|
||||
<p><a class="btn btn-secondary" href="fw-editor.cgi?f=<%= $(get_config) %>">Edit Configuration</a></p>
|
||||
<p><a class="btn btn-danger" href="fw-restore.cgi?f=<%= $(get_config) %>">Reset Configuration</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
120
cgi-bin/mj-endpoints.cgi
Executable file
120
cgi-bin/mj-endpoints.cgi
Executable file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Majestic Endpoints" %>
|
||||
|
||||
<%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>Video</h3>
|
||||
<dl>
|
||||
<dt class="cp2cb">rtsp://root:12345@<%= $network_address %>/stream=0</dt>
|
||||
<dd>RTSP main stream.</dd>
|
||||
<dt class="cp2cb">rtsp://root:12345@<%= $network_address %>/stream=1</dt>
|
||||
<dd>RTSP sub stream.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/mjpeg</dt>
|
||||
<dd>MJPEG video stream.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/video.mp4</dt>
|
||||
<dd>MP4 video stream.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/hls</dt>
|
||||
<dd>HLS live-streaming in web browser.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/mjpeg.html</dt>
|
||||
<dd>MJPEG live-streaming in web browser.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Audio</h3>
|
||||
<dl>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/audio.opus</dt>
|
||||
<dd>Opus audio stream.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/audio.m4a</dt>
|
||||
<dd>AAC 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.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 speaker.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Images</h3>
|
||||
<dl>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/image.jpg</dt>
|
||||
<dd>Snapshot in JPEG format.</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>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Night</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 night mode.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/night/ircut</dt>
|
||||
<dd>Toggle camera ircut.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/night/light</dt>
|
||||
<dd>Toggle camera light.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Monitoring</h3>
|
||||
<dl>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/api/v1/config.json</dt>
|
||||
<dd>Default Majestic config in JSON format.</dd>
|
||||
<dt class="cp2cb">http://<%= $network_address %>/api/v1/config.schema.json</dt>
|
||||
<dd>Available Majestic settings in JSON format.</dd>
|
||||
<dt><a href="https://github.com/openipc/wiki/blob/master/en/majestic-config.md">https://github.com/openipc/wiki</a></dt>
|
||||
<dd>Available Majestic settings in YAML 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>
|
||||
|
||||
<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 %>
|
||||
169
cgi-bin/mj-settings.cgi
Executable file
169
cgi-bin/mj-settings.cgi
Executable file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
|
||||
<%
|
||||
page_title="Majestic Settings"
|
||||
label="$GET_tab"
|
||||
[ -z "$label" ] && label="system"
|
||||
|
||||
json_conf=$(wget -q -T1 localhost/api/v1/config.json -O -)
|
||||
json_schema=$(cat $(get_schema) | jsonfilter -e "@.properties.$label")
|
||||
json_load "$json_schema"
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
case "$POST_action" in
|
||||
restart)
|
||||
killall -1 majestic
|
||||
;;
|
||||
|
||||
update)
|
||||
OIFS=$IFS
|
||||
IFS=$'\n'
|
||||
for yaml_param in $(printenv | grep POST__ | sort); do
|
||||
param=$(echo ${yaml_param#POST_} | cut -d= -f1)
|
||||
newval=$(echo ${yaml_param#POST_} | cut -d= -f2)
|
||||
setting=${param//_/.}
|
||||
oldval=$(yaml-cli -g "$setting")
|
||||
|
||||
if [ -z "$newval" ] && [ -n "$oldval" ]; then
|
||||
yaml-cli -d "$setting"
|
||||
elif [ "$newval" != "$oldval" ]; then
|
||||
yaml-cli -s "$setting" "$newval"
|
||||
fi
|
||||
done
|
||||
IFS=$OIFS
|
||||
;;
|
||||
esac
|
||||
|
||||
redirect_to "$HTTP_REFERER"
|
||||
fi
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<% if [ -z "$(pidof majestic)" ]; then %>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
<h4>Majestic is not running.</h4>
|
||||
<p>Go to https://wiki.openipc.org for more information.</p>
|
||||
</div>
|
||||
|
||||
<% else %>
|
||||
|
||||
<ul class="nav nav-underline small mb-4 d-lg-flex">
|
||||
<%
|
||||
include j/locale.cgi
|
||||
eval $(cat $(get_schema) | jsonfilter -e "section=@.properties")
|
||||
for key in $section; do
|
||||
locale=$(eval echo \$mj_${key})
|
||||
if [ -n "$locale" ]; then
|
||||
c="class=\"nav-link\""
|
||||
[ "$label" = "$key" ] && title="$locale" && c="class=\"nav-link active\" aria-current=\"true\""
|
||||
echo "<li class=\"nav-item\"><a ${c} href=\"mj-settings.cgi?tab=${key}\">${locale}</a></li>"
|
||||
fi
|
||||
done
|
||||
%>
|
||||
</ul>
|
||||
|
||||
<% if [ -n "$title" ]; then %>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<h3><%= $title %></h3>
|
||||
<div class="d-grid gap-2">
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<%
|
||||
json_select "properties"
|
||||
json_get_keys "keys"
|
||||
for key in $keys; do
|
||||
json_select "$key"
|
||||
json_get_var "desc" "description"
|
||||
json_get_var "type" "type"
|
||||
json_get_values "enum" "enum"
|
||||
json_get_var "min" "minimum"
|
||||
json_get_var "max" "maximum"
|
||||
json_select ..
|
||||
|
||||
param="_${label}_${key}"
|
||||
setting=${param//_/.}
|
||||
value=$(yaml-cli -g "$setting")
|
||||
default=${value:-$(echo "$json_conf" | jsonfilter -e "@$setting")}
|
||||
config="${config}\n$(echo $setting: $value)"
|
||||
|
||||
case "$type" in
|
||||
boolean)
|
||||
field_switch "$param" "$desc" "$default"
|
||||
;;
|
||||
|
||||
integer)
|
||||
if [ -n "$max" ] && [ "$max" -le "100" ]; then
|
||||
field_range "$param" "$desc" "$default" "$min" "$max"
|
||||
else
|
||||
field_integer "$param" "$desc" "$default" "$min" "$max"
|
||||
fi
|
||||
;;
|
||||
|
||||
string)
|
||||
field_string "$param" "$desc" "$default" "$enum"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
%>
|
||||
<input type="hidden" name="action" value="update">
|
||||
<% button_submit %>
|
||||
</form>
|
||||
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<input type="hidden" name="action" value="restart">
|
||||
<% button_submit "Restart Majestic" "secondary" %>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Related Settings</h3>
|
||||
<pre><% echo -e "$config" %></pre>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Quick Links</h3>
|
||||
<p><a href="mj-configuration.cgi">Majestic Configuration</a></p>
|
||||
<p><a href="mj-endpoints.cgi">Majestic Endpoints</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if [ "$label" = "motionDetect" ]; then %>
|
||||
<%in p/roi.cgi %>
|
||||
<% fi %>
|
||||
|
||||
<% else %>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
<h4>Setting is not available.</h4>
|
||||
<p><a href="mj-settings.cgi">Majestic Settings</a></p>
|
||||
</div>
|
||||
|
||||
<% fi %>
|
||||
<% fi %>
|
||||
|
||||
<script>
|
||||
<% if [ -e /etc/sensors ]; then %>
|
||||
if ($("#_isp_sensorConfig")) {
|
||||
const inp = $("#_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 $(find /etc/sensors -type f -maxdepth 1); do %>
|
||||
opt = new Option("<%= $i %>");
|
||||
opt.selected = ("<%= $i %>" == inp.value);
|
||||
sel.options.add(opt);
|
||||
<% done %>
|
||||
inp.replaceWith(sel);
|
||||
}
|
||||
<% fi %>
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
38
cgi-bin/p/address.cgi
Executable file
38
cgi-bin/p/address.cgi
Executable file
@ -0,0 +1,38 @@
|
||||
<h3>This camera uses MAC address <b>00:00:23:34:45:66</b> which is a placeholder.</h3>
|
||||
<p>You need to replace it with the original MAC address from your stock firmware backup or <a href="#" id="generate-mac-address">generate a random valid MAC address</a>.</p>
|
||||
<form action="fw-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">New MAC Address</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="Change MAC address"></div>
|
||||
</form>
|
||||
<p class="mb-0">Please note that the new MAC address will most likely give the camera a new IP address assigned by the DHCP server!</p>
|
||||
|
||||
<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("There's a value in MAC address field. Please empty the field and try again.");
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
document.querySelector('#generate-mac-address').addEventListener('click', generateMacAddress);
|
||||
});
|
||||
</script>
|
||||
504
cgi-bin/p/common.cgi
Executable file
504
cgi-bin/p/common.cgi
Executable file
@ -0,0 +1,504 @@
|
||||
#!/usr/bin/haserl
|
||||
<%
|
||||
IFS_ORIG=$IFS
|
||||
|
||||
# tag "text" "classes" "extras"
|
||||
div() {
|
||||
tag "div" "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
# tag "tag" "text" "css" "extras"
|
||||
tag() {
|
||||
local t="$1"
|
||||
local n="$2"
|
||||
local c="$3"
|
||||
[ -n "$c" ] && c=" class=\"${c}\""
|
||||
local x="$4"
|
||||
[ -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}>"
|
||||
}
|
||||
|
||||
d() {
|
||||
echo "$1" >&2
|
||||
}
|
||||
|
||||
e() {
|
||||
echo -e -n "$1"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
row_() {
|
||||
echo "<div class\"row ${1}\" ${2}>"
|
||||
}
|
||||
|
||||
_row() {
|
||||
echo "</div>"
|
||||
}
|
||||
|
||||
row() {
|
||||
row_ "$2"
|
||||
echo "$1"
|
||||
_row
|
||||
}
|
||||
|
||||
span_() {
|
||||
A "span" "$1" "$2"
|
||||
}
|
||||
|
||||
_span() {
|
||||
Z "span"
|
||||
}
|
||||
|
||||
# alert "text" "type" "extras"
|
||||
alert() {
|
||||
echo "<div class=\"alert alert-${2}\" ${3}>${1}</div>"
|
||||
}
|
||||
|
||||
# button_submit "text" "type" "extras"
|
||||
button_submit() {
|
||||
local t="$1"
|
||||
[ -z "$t" ] && t="Save Changes"
|
||||
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>"
|
||||
}
|
||||
|
||||
check_password() {
|
||||
local p="/cgi-bin/fw-interface.cgi"
|
||||
[ -z "$SCRIPT_NAME" ] || [ "$SCRIPT_NAME" = "${p}" ] && return
|
||||
if [ ! -f /etc/shadow- ] || [ -z $(grep root /etc/shadow- | cut -d: -f2) ]; then
|
||||
redirect_to "${p}" "danger" "You must set your own secure password!"
|
||||
fi
|
||||
}
|
||||
|
||||
ex() {
|
||||
echo "<div class=\"${2:-ex}\"><h6># ${1}</h6><pre class=\"small\">"
|
||||
eval "$1" | sed "s/&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g"
|
||||
echo "</pre></div>"
|
||||
}
|
||||
|
||||
# field_hidden "name" "value"
|
||||
field_hidden() {
|
||||
local n="$1"
|
||||
local v="$2"
|
||||
echo "<input type=\"hidden\" name=\"${n}\" id=\"${n}\" value=\"${v}\" class=\"form-hidden\">"
|
||||
}
|
||||
|
||||
# field_integer "name" "label" "value" "min" "max" "hint"
|
||||
field_integer() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local v="$3"
|
||||
local x="$4"
|
||||
local y="$5"
|
||||
local h="$6"
|
||||
echo "<p class=\"number\">" \
|
||||
"<label class=\"form-label\" for=\"${n}\">${l}</label>" \
|
||||
"<span class=\"input-group\">"
|
||||
echo "<input type=\"number\" id=\"${n}\" name=\"${n}\" class=\"form-control text-end\" value=\"${v}\" min=\"${x}\" max=\"${y}\" step=\"1\">" \
|
||||
"</span>"
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_password "name" "label" "hint"
|
||||
field_password() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local h="$3"
|
||||
local v=$(t_value "$n")
|
||||
echo "<p class=\"password\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label><span class=\"input-group\">" \
|
||||
"<input type=\"password\" id=\"${n}\" name=\"${n}\" class=\"form-control\" value=\"${v}\">" \
|
||||
"<label class=\"input-group-text\">" \
|
||||
"<input type=\"checkbox\" class=\"form-check-input me-1\" data-for=\"${n}\"> show" \
|
||||
"</label></span>"
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_range "name" "label" "value" "min" "max" "hint"
|
||||
field_range() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local v="$3"
|
||||
local x="$4"
|
||||
local y="$5"
|
||||
local h="$6"
|
||||
echo "<p class=\"range\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label>" \
|
||||
"<span class=\"input-group\">"
|
||||
echo "<input type=\"hidden\" id=\"${n}\" name=\"${n}\" value=\"${v}\">"
|
||||
echo "<input type=\"range\" class=\"form-control form-range\" id=\"${n}-range\" value=\"${v}\" min=\"${x}\" max=\"${y}\" step=\"1\">"
|
||||
echo "<span class=\"input-group-text show-value\" id=\"${n}-show\">${v}</span></span>"
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_switch "name" "label" "value" "hint"
|
||||
field_switch() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local v="$3"
|
||||
local h="$4"
|
||||
[ "$v" = "eval" ] && v=$(t_value "$n")
|
||||
[ "$v" = "true" ] && v="checked"
|
||||
echo "<p class=\"boolean\"><span class=\"form-check form-switch\">" \
|
||||
"<input type=\"hidden\" id=\"${n}-false\" name=\"${n}\" value=\"false\">" \
|
||||
"<input type=\"checkbox\" id=\"${n}\" name=\"${n}\" value=\"true\" class=\"form-check-input\" ${v}>" \
|
||||
"<label for=\"${n}\" class=\"form-check-label\">${l}</label></span>"
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_string "name" "label" "value" "enum" "hint"
|
||||
field_string() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local v="$3"
|
||||
local e="$4"
|
||||
local h="$5"
|
||||
[ "$v" = "eval" ] && v=$(t_value "$n")
|
||||
if [ -n "$e" ]; then
|
||||
echo "<p class=\"select\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label>" \
|
||||
"<select class=\"form-select\" id=\"${n}\" name=\"${n}\">"
|
||||
for e in $e; do
|
||||
echo -n "<option value=\"${e}\""
|
||||
[ "$v" = "$e" ] && echo -n " selected"
|
||||
echo ">${e}</option>"
|
||||
done
|
||||
echo "</select>"
|
||||
else
|
||||
echo "<p class=\"string\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label>" \
|
||||
"<input type=\"text\" id=\"${n}\" name=\"${n}\" class=\"form-control\" value=\"${v}\">"
|
||||
fi
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_text "name" "label" "hint"
|
||||
field_text() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local h="$3"
|
||||
local v=$(t_value "$n")
|
||||
echo "<p class=\"string\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label>" \
|
||||
"<input type=\"text\" id=\"${n}\" name=\"${n}\" class=\"form-control\" value=\"${v}\">"
|
||||
[ -n "$h" ] && echo "<span class=\"hint text-secondary\">${h}</span>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
# field_textedit "name" "label" "file"
|
||||
field_textedit() {
|
||||
local n="$1"
|
||||
local l="$2"
|
||||
local v=$(cat "$3")
|
||||
echo "<p class=\"textarea\" id=\"${n}_wrap\">" \
|
||||
"<label for=\"${n}\" class=\"form-label\">${l}</label>" \
|
||||
"<textarea id=\"${n}\" name=\"${n}\" class=\"form-control\">${v}</textarea>"
|
||||
echo "</p>"
|
||||
}
|
||||
|
||||
get_config() {
|
||||
echo ${1}/etc/majestic.yaml
|
||||
}
|
||||
|
||||
get_metrics() {
|
||||
local m=$(pidof majestic)
|
||||
if [ -z "$m" ]; then
|
||||
echo 0
|
||||
else
|
||||
wget -q -T1 localhost/metrics/night?value=${1} -O -
|
||||
fi
|
||||
}
|
||||
|
||||
get_schema() {
|
||||
local m=/tmp/webui/schema.json
|
||||
if [ ! -e "$m" ]; then
|
||||
wget -q -T1 localhost/api/v1/config.schema.json -O "$m"
|
||||
fi
|
||||
echo "$m"
|
||||
}
|
||||
|
||||
get_night() {
|
||||
local m=$(pidof majestic)
|
||||
local v=$(yaml-cli -g .nightMode.$1)
|
||||
if [ -n "$m" ] && [ -n "$v" ] && [ "$v" != "false" ]; then
|
||||
echo true
|
||||
else
|
||||
echo false
|
||||
fi
|
||||
}
|
||||
|
||||
log_create() {
|
||||
echo "${1}:${2}" > "$log_file"
|
||||
}
|
||||
|
||||
log_read() {
|
||||
[ ! -f "$log_file" ] && return
|
||||
[ -z "$(cat $log_file)" ] && return
|
||||
local c
|
||||
local m
|
||||
local l
|
||||
OIFS="$IFS"
|
||||
IFS=$'\n'
|
||||
for l in $(cat "$log_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
|
||||
rm -f "$log_file"
|
||||
}
|
||||
|
||||
set_error_flag() {
|
||||
echo "danger:${1}" >> "$log_file"
|
||||
error=1
|
||||
}
|
||||
|
||||
html_title() {
|
||||
[ -n "$page_title" ] && echo -n "$page_title"
|
||||
[ -n "$title" ] && echo -n ": $title"
|
||||
echo -n " - OpenIPC"
|
||||
}
|
||||
|
||||
include() {
|
||||
[ -f "$1" ] && . "$1"
|
||||
}
|
||||
|
||||
# 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>"
|
||||
}
|
||||
|
||||
# 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() {
|
||||
if [ "true" = "$(yaml-cli -g .jpeg.enabled)" ]; then
|
||||
echo "<video poster=\"/mjpeg\" style=\"background:url(/a/preview.svg); background-size:cover; width:100%\"></video>"
|
||||
else
|
||||
echo "<p class=\"alert alert-warning\"><a href=\"mj-settings.cgi?tab=jpeg\">Enable JPEG support</a> to see the preview.</p>"
|
||||
fi
|
||||
}
|
||||
|
||||
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" ] && log_create "$2" "$3"
|
||||
echo "HTTP/1.1 303 See Other"
|
||||
echo "Content-type: text/html; charset=UTF-8"
|
||||
echo "Cache-Control: no-store"
|
||||
echo "Pragma: no-cache"
|
||||
echo "Location: $1"
|
||||
echo
|
||||
exit 0
|
||||
}
|
||||
|
||||
report_command() {
|
||||
echo "<h4># ${1}</h4>"
|
||||
echo "<pre class=\"small\">${2}</pre>"
|
||||
}
|
||||
|
||||
report_error() {
|
||||
echo "<h4 class=\"text-danger\">Oops. Something happened.</h4>"
|
||||
alert "$1" "danger"
|
||||
}
|
||||
|
||||
# report_log "text" "extras"
|
||||
report_log() {
|
||||
pre "$1" "small" "$2"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
t_label() {
|
||||
eval "echo \$tL_${1}"
|
||||
}
|
||||
|
||||
t_value() {
|
||||
eval "echo \$${1}"
|
||||
}
|
||||
|
||||
update_caminfo() {
|
||||
flash_type=$(ipcinfo --flash-type)
|
||||
mtd_size=$(grep -E "nor|nand" $(ls /sys/class/mtd/mtd*/type) | sed -E "s|type.+|size|g")
|
||||
flash_size=$(awk '{sum+=$1} END{print sum/1024/1024}' $mtd_size)
|
||||
|
||||
sensor_ini=$(ipcinfo --long-sensor)
|
||||
sensor=$(fw_printenv -n sensor)
|
||||
[ -z "$sensor" ] && sensor=$(echo $sensor_ini | cut -d_ -f1)
|
||||
|
||||
soc_vendor=$(ipcinfo --vendor)
|
||||
soc_family=$(ipcinfo --family)
|
||||
|
||||
soc=$(ipcinfo --chip-name)
|
||||
if [ -z "$soc" ] || [ "$soc_vendor" = "sigmastar" ]; then
|
||||
soc=$(fw_printenv -n soc)
|
||||
fi
|
||||
|
||||
soc_temp=$(ipcinfo --temp 2> /dev/null)
|
||||
if [ -n "$soc_temp" ]; then
|
||||
soc_has_temp="true"
|
||||
else
|
||||
soc_has_temp="false"
|
||||
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 '"')
|
||||
fw_build=$(grep "GITHUB_VERSION" /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
mj_version=$($mj_bin_file -v)
|
||||
uboot_version=$(fw_printenv -n ver)
|
||||
|
||||
# WebUI
|
||||
ui_password=$(grep root /etc/shadow | cut -d: -f2)
|
||||
ptz_support=$(fw_printenv -n ptz)
|
||||
|
||||
# Network
|
||||
network_interface=$(ip route | awk '/default/ {print $5}' | head -n1)
|
||||
network_address=$(ip route | grep ${network_interface:-eth0} | awk '/src/ {print $7}')
|
||||
network_gateway=$(ip route | awk '/default/ {print $3}')
|
||||
network_hostname=$(hostname -s)
|
||||
network_macaddr=$(cat /sys/class/net/${network_interface:-eth0}/address)
|
||||
|
||||
# Overlay
|
||||
overlay_root="/overlay"
|
||||
|
||||
# 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 variables="flash_size flash_type fw_build fw_variant fw_version mj_version network_address
|
||||
network_gateway network_hostname network_interface network_macaddr overlay_root ptz_support
|
||||
sensor sensor_ini soc soc_family soc_has_temp soc_vendor tz_data tz_name uboot_version ui_password"
|
||||
rm -f ${sysinfo_file}
|
||||
|
||||
local v
|
||||
for v in $variables; do
|
||||
eval "echo ${v}=\'\$${v}\' >> ${sysinfo_file}"
|
||||
done
|
||||
|
||||
generate_signature
|
||||
}
|
||||
|
||||
mj_bin_file=/usr/bin/majestic
|
||||
log_file=/tmp/webui/logfile.txt
|
||||
signature_file=/tmp/webui/signature.txt
|
||||
sysinfo_file=/tmp/webui/sysinfo.txt
|
||||
|
||||
[ ! -d /etc/webui ] && mkdir -p /etc/webui
|
||||
[ ! -d /tmp/webui ] && mkdir -p /tmp/webui
|
||||
|
||||
[ ! -f $sysinfo_file ] && update_caminfo
|
||||
include $sysinfo_file
|
||||
|
||||
pagename=$(basename "$SCRIPT_NAME")
|
||||
pagename="${pagename%%.*}"
|
||||
|
||||
include /etc/webui/webui.conf
|
||||
include /usr/share/libubox/jshn.sh
|
||||
|
||||
check_password
|
||||
%>
|
||||
16
cgi-bin/p/footer.cgi
Executable file
16
cgi-bin/p/footer.cgi
Executable file
@ -0,0 +1,16 @@
|
||||
</div>
|
||||
</main>
|
||||
<footer class="x-small">
|
||||
<div class="container pt-3">
|
||||
<div class="row">
|
||||
<div class="col col-2">
|
||||
<p id="uptime" class="text-secondary"></p>
|
||||
</div>
|
||||
<div class="col col-10">
|
||||
<p class="text-end"><a href="https://github.com/openipc/majestic-webui">WebUI</a> by <a href="https://openipc.org/">OpenIPC</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
131
cgi-bin/p/header.cgi
Executable file
131
cgi-bin/p/header.cgi
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/haserl
|
||||
Content-type: text/html; charset=UTF-8
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="<%= ${webui_theme:=dark} %>">
|
||||
<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 %>">
|
||||
<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="32" src="/a/logo.svg"><span class="x-small ms-1"><%= $fw_variant %></span></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 dropdown">
|
||||
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownInformation" role="button">Information</a>
|
||||
<ul aria-labelledby="dropdownInformation" class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="status.cgi">Status</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="info-majestic.cgi">Majestic</a></li>
|
||||
<li><a class="dropdown-item" href="info-kernel.cgi">Kernel</a></li>
|
||||
<li><a class="dropdown-item" href="info-overlay.cgi">Overlay</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">Majestic</a>
|
||||
<ul aria-labelledby="dropdownMajestic" class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="mj-settings.cgi">Settings</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="mj-configuration.cgi">Configuration</a></li>
|
||||
<li><a class="dropdown-item" href="mj-endpoints.cgi">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="dropdownSettings" role="button">Firmware</a>
|
||||
<ul aria-labelledby="dropdownSettings" class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="fw-network.cgi">Network</a></li>
|
||||
<li><a class="dropdown-item" href="fw-time.cgi">Time</a></li>
|
||||
<li><a class="dropdown-item" href="fw-interface.cgi">Interface</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="fw-update.cgi">Update</a></li>
|
||||
<li><a class="dropdown-item" href="fw-settings.cgi">Settings</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">Tools</a>
|
||||
<ul aria-labelledby="dropdownTools" class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="tool-console.cgi">Console</a></li>
|
||||
<li><a class="dropdown-item" href="tool-files.cgi">Files</a></li>
|
||||
<% if [ -e /dev/mmcblk0 ]; then %>
|
||||
<li><a class="dropdown-item" href="tool-sdcard.cgi">SDcard</a></li>
|
||||
<% fi %>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownExtensions" role="button">Extensions</a>
|
||||
<ul aria-labelledby="dropdownExtensions" class="dropdown-menu dropdown-menu-lg-end">
|
||||
<li><a class="dropdown-item" href="ext-openwall.cgi">OpenWall</a></li>
|
||||
<li><a class="dropdown-item" href="ext-telegram.cgi">Telegram</a></li>
|
||||
<li><a class="dropdown-item" href="ext-tunnel.cgi">Tunnel</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="ext-proxy.cgi">Proxy</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="preview.cgi">Preview</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="pb-4">
|
||||
<div class="container" style="min-height: 85vh">
|
||||
<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-6 mb-2">
|
||||
<%= $(signature) %>
|
||||
</div>
|
||||
|
||||
<div class="col-1" id="daynight_value"></div>
|
||||
<div class="col-md-4 col-lg-3 mb-2 text-end">
|
||||
<div id="time-now"></div>
|
||||
<div class="text-secondary" id="soc-temp"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if [ -z "$network_gateway" ]; then %>
|
||||
<div class="alert alert-warning">
|
||||
<p class="mb-0">Internet connection not available, please <a href="fw-network.cgi">check your network settings</a>.</p>
|
||||
</div>
|
||||
<% fi %>
|
||||
|
||||
<% if [ "$network_macaddr" = "00:00:23:34:45:66" ] && [ -f /etc/shadow- ] && [ -n $(grep root /etc/shadow- | cut -d: -f2) ]; then %>
|
||||
<div class="alert alert-danger">
|
||||
<%in p/address.cgi %>
|
||||
</div>
|
||||
<% fi %>
|
||||
|
||||
<% if [ ! -e $(get_config) ]; then %>
|
||||
<div class="alert alert-danger">
|
||||
<p class="mb-0">Majestic configuration not found, please <a href="mj-configuration.cgi">check your Majestic settings</a>.</p>
|
||||
</div>
|
||||
<% fi %>
|
||||
|
||||
<% if [ "$(cat /etc/TZ)" != "$TZ" ] || [ -e /tmp/system-reboot ]; then %>
|
||||
<div class="alert alert-danger">
|
||||
<h3>Warning.</h3>
|
||||
<p>System settings have been updated, restart to apply pending changes.</p>
|
||||
<span class="d-flex gap-3">
|
||||
<a class="btn btn-danger" href="fw-restart.cgi">Restart camera</a>
|
||||
</span>
|
||||
</div>
|
||||
<% fi %>
|
||||
|
||||
<h2><%= $page_title %></h2>
|
||||
<% log_read %>
|
||||
32
cgi-bin/p/motor.cgi
Executable file
32
cgi-bin/p/motor.cgi
Executable file
@ -0,0 +1,32 @@
|
||||
<hr class="mb-3"/>
|
||||
<div class="motor">
|
||||
<div class="col">
|
||||
<button class="btn btn-motor" data-dir="ul">↖️</button>
|
||||
<button class="btn btn-motor" data-dir="uc">⬆️</button>
|
||||
<button class="btn btn-motor" data-dir="ur">↗️</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="btn btn-motor" data-dir="lc">⬅️</button>
|
||||
<button class="btn btn-motor" data-dir="cc">🆗</button>
|
||||
<button class="btn btn-motor" data-dir="rc">➡️</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="btn btn-motor" data-dir="dl">↙️</button>
|
||||
<button class="btn btn-motor" data-dir="dc">⬇️</button>
|
||||
<button class="btn btn-motor" data-dir="dr">↘️</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function control(dir) {
|
||||
let x = dir.includes("l") ? -1 : dir.includes("r") ? 1 : 0;
|
||||
let y = dir.includes("d") ? -1 : dir.includes("u") ? 1 : 0;
|
||||
fetch('/cgi-bin/j/run.cgi?web=' + btoa('motor ' + '<%= $ptz_support %> ' + x + ' ' + y));
|
||||
}
|
||||
|
||||
$$(".motor button").forEach(el => {
|
||||
el.addEventListener("click", ev => {
|
||||
control(ev.target.dataset.dir);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
18
cgi-bin/p/roi.cgi
Executable file
18
cgi-bin/p/roi.cgi
Executable file
@ -0,0 +1,18 @@
|
||||
<div class="col-10" id="_row">
|
||||
<h3>Visual editor</h3>
|
||||
<div class="col">
|
||||
<iframe id="_iframe" src="/m/img.html" frameborder="0" style="padding: 0px; margin: 0px; border: 1px solid rgb(76, 96, 216);"></iframe>
|
||||
</div>
|
||||
<div class="row mb-3 align-items-center">
|
||||
<div class="col">
|
||||
<input type="button" class="btn btn-primary" onclick="_clear();" value="Clear all regions">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function _clear() {
|
||||
document.getElementById('_iframe').contentWindow.location.reload();
|
||||
document.getElementById('_motionDetect_roi').value = '';
|
||||
}
|
||||
</script>
|
||||
69
cgi-bin/preview.cgi
Executable file
69
cgi-bin/preview.cgi
Executable file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
|
||||
<% page_title="Camera Preview" %>
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<div class="row preview">
|
||||
<div class="col">
|
||||
<% preview %>
|
||||
<p class="small"><a href="mj-endpoints.cgi">Majestic Endpoints</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<% if [ "$(get_night lightMonitor)" = "true" ]; then %>
|
||||
<p class="small"><a href="mj-settings.cgi?tab=nightMode">Light monitor active</a></p>
|
||||
<% fi %>
|
||||
|
||||
<div class="d-grid gap-3">
|
||||
<input type="checkbox" class="btn-check" id="toggle-night">
|
||||
<label class="btn btn-primary" for="toggle-night">Night</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" id="toggle-ircut">
|
||||
<label class="btn btn-primary" for="toggle-ircut">IRcut</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" id="toggle-light">
|
||||
<label class="btn btn-primary" for="toggle-light">Light</label>
|
||||
|
||||
<% if [ -n "$ptz_support" ]; then %>
|
||||
<%in p/motor.cgi %>
|
||||
<% fi %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<% echo "\$('#toggle-night').checked = $(get_metrics night_enabled);" %>
|
||||
<% echo "\$('#toggle-ircut').checked = $(get_metrics ircut_enabled);" %>
|
||||
<% echo "\$('#toggle-light').checked = $(get_metrics light_enabled);" %>
|
||||
|
||||
<% echo "\$('#toggle-night').disabled = $(get_night lightMonitor);" %>
|
||||
<% echo "\$('#toggle-ircut').disabled = $(get_night lightMonitor) || !$(get_night irCutPin1);" %>
|
||||
<% echo "\$('#toggle-light').disabled = $(get_night lightMonitor) || !$(get_night backlightPin);" %>
|
||||
|
||||
$("#toggle-night").addEventListener("click", ev => {
|
||||
fetch('/night/toggle').then(api => api.json()).then(data => {
|
||||
ev.checked = data;
|
||||
if (!$('#toggle-ircut').disabled) {
|
||||
$('#toggle-ircut').checked = data;
|
||||
}
|
||||
if (!$('#toggle-light').disabled) {
|
||||
$('#toggle-light').checked = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#toggle-ircut").addEventListener("click", ev => {
|
||||
fetch('/night/ircut').then(api => api.json()).then(data => {
|
||||
ev.checked = data;
|
||||
});
|
||||
});
|
||||
|
||||
$("#toggle-light").addEventListener("click", ev => {
|
||||
fetch('/night/light').then(api => api.json()).then(data => {
|
||||
ev.checked = data;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
48
cgi-bin/status.cgi
Executable file
48
cgi-bin/status.cgi
Executable file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
|
||||
<% page_title="Device Status" %>
|
||||
<%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>Hardware</h3>
|
||||
<dl class="small list">
|
||||
<dt>Processor</dt>
|
||||
<dd><%= $soc %></dd>
|
||||
<dt>Family</dt>
|
||||
<dd><%= $soc_family %></dd>
|
||||
<dt>Sensor</dt>
|
||||
<dd><%= $sensor_ini %></dd>
|
||||
<dt>Flash</dt>
|
||||
<dd><%= $flash_size %> MB</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Firmware</h3>
|
||||
<dl class="small list">
|
||||
<dt>Version</dt>
|
||||
<dd><%= "${fw_version}-${fw_variant}" %></dd>
|
||||
<dt>Build</dt>
|
||||
<dd><%= $fw_build %></dd>
|
||||
<dt>Majestic</dt>
|
||||
<dd><%= $mj_version %></dd>
|
||||
<% if [ -n "$uboot_version" ]; then %>
|
||||
<dt>U-Boot</dt>
|
||||
<dd><%= $uboot_version %></dd>
|
||||
<% fi %>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col ">
|
||||
<h3>Resources</h3>
|
||||
<% ex "uptime" %>
|
||||
<% ex "df -hT" %>
|
||||
<% ex "free -h" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
41
cgi-bin/tool-console.cgi
Executable file
41
cgi-bin/tool-console.cgi
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<%
|
||||
page_title="Console"
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<% field_text "command" "Enter command:" %>
|
||||
</div>
|
||||
<div class="col align-self-center">
|
||||
<% button_submit "Run" "secondary" %>
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<div id="output-wrapper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
$('form').addEventListener('submit', event => {
|
||||
event.preventDefault();
|
||||
$('form input[type=submit]').disabled = true;
|
||||
cmd = $('#command').value;
|
||||
|
||||
el = document.createElement('pre')
|
||||
el.id = "output";
|
||||
el.dataset['cmd'] = cmd;
|
||||
|
||||
h6 = document.createElement('h6')
|
||||
$('#output-wrapper').innerHTML = '';
|
||||
$('#output-wrapper').appendChild(h6);
|
||||
$('#output-wrapper').appendChild(el);
|
||||
|
||||
runCmd("web")
|
||||
});
|
||||
</script>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
43
cgi-bin/tool-files.cgi
Executable file
43
cgi-bin/tool-files.cgi
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
<% page_title="Files" %>
|
||||
<%
|
||||
[ -n "$GET_cd" ] && dir=${GET_cd}
|
||||
dir=$(cd ${dir:-/}; pwd | sed s#^//#/#)
|
||||
back=$(cd ${dir}/..; pwd | sed s#^//#/#)
|
||||
%>
|
||||
|
||||
<%in p/header.cgi %>
|
||||
<h4><%= $dir %></h4>
|
||||
<%
|
||||
echo "<div class=\"row mb-3\">"
|
||||
echo "<a href=\"?cd=${back}\" class=\"fw-bold\">..</a>"
|
||||
echo "</div>"
|
||||
|
||||
filename=$(ls --group-directories-first $dir)
|
||||
for line in $filename; do
|
||||
path=$(echo "${dir}/${line}" | sed s!^//!/!)
|
||||
[ "$path" = "/proc" ] || [ "$path" = "/sys" ] && continue
|
||||
|
||||
echo "<div class=\"row mb-3\">"
|
||||
echo "<div class=\"col-10 col-lg-4\">"
|
||||
if [ -d "${path}" ]; then
|
||||
echo "<a href=\"?cd=${path}\" class=\"fw-bold\">${line}</a>"
|
||||
else
|
||||
echo "<a href=\"${path}\" class=\"fst-italic\">${line}</a>"
|
||||
fi
|
||||
|
||||
fileinfo=$(stat -c "%s.%a.%z" $path)
|
||||
filesize=$(echo $fileinfo | cut -d. -f1)
|
||||
permission=$(echo $fileinfo | cut -d. -f2)
|
||||
timestamp=$(echo $fileinfo | cut -d. -f3)
|
||||
|
||||
echo "</div>"
|
||||
echo "<div class=\"col-2 col-lg-2 font-monospace text-end\">${filesize}</div>"
|
||||
echo "<div class=\"col-6 col-lg-2 font-monospace text-center\">${permission}</div>"
|
||||
echo "<div class=\"col-6 col-lg-2 font-monospace text-end\">${timestamp}</div>"
|
||||
echo "</div>"
|
||||
done
|
||||
%>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
105
cgi-bin/tool-sdcard.cgi
Executable file
105
cgi-bin/tool-sdcard.cgi
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/haserl
|
||||
<%in p/common.cgi %>
|
||||
|
||||
<% page_title="SDcard" %>
|
||||
<%in p/header.cgi %>
|
||||
|
||||
<% if [ ! -e /dev/mmcblk0 ]; then %>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
<h4>SDcard is not available.</h4>
|
||||
<p>Make sure the card is correctly inserted.</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>SDcard formatting takes time.</h4>
|
||||
<p>Please do not refresh this page. Wait until partition formatting is finished!</p>
|
||||
</div>
|
||||
|
||||
<%
|
||||
if [ "$(grep $card_partition /etc/mtab)" ]; then
|
||||
_c="umount $card_partition"
|
||||
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||
[ $? -ne 0 ] && error="Cannot unmount SDcard partition."
|
||||
fi
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
_c="mkfs.vfat $card_partition"
|
||||
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||
[ $? -ne 0 ] && error="Cannot format SDcard partition."
|
||||
fi
|
||||
|
||||
if [ -z "$error" ] && [ ! -d "$mount_point" ]; then
|
||||
_c="mkdir -p $mount_point"
|
||||
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||
[ $? -ne 0 ] && error="Cannot create SDcard mount point."
|
||||
fi
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
_c="mount -t vfat $card_partition $mount_point"
|
||||
_o="${_o}\n${_c}\n$($_c 2>&1)"
|
||||
[ $? -ne 0 ] && error="Cannot remount SDcard partition."
|
||||
fi
|
||||
|
||||
if [ -n "$error" ]; then
|
||||
report_error "$error"
|
||||
[ -n "$_c" ] && report_command "$_c" "$_o"
|
||||
else
|
||||
report_log "$_o"
|
||||
fi
|
||||
%>
|
||||
|
||||
<a class="btn btn-primary" href="/">Return</a>
|
||||
|
||||
<% else %>
|
||||
|
||||
<h4>SDcard partitions</h4>
|
||||
<%
|
||||
partitions=$(df -h | grep 'dev/mmc')
|
||||
echo "<pre class=\"small\">${partitions}</pre>"
|
||||
%>
|
||||
|
||||
<% if [ -n "$partitions" ]; then %>
|
||||
|
||||
<h4>Browse files on these partitions</h4>
|
||||
<div class="mb-4">
|
||||
<%
|
||||
IFS=$'\n'
|
||||
for i in $partitions; do
|
||||
_mount=$(echo $i | awk '{print $6}')
|
||||
echo "<a href=\"tool-files.cgi?cd=${_mount}\" class=\"btn btn-primary\">${_mount}</a>"
|
||||
unset _mount
|
||||
done
|
||||
IFS=$IFS_ORIG
|
||||
unset _partitions
|
||||
%>
|
||||
</div>
|
||||
|
||||
<% fi %>
|
||||
|
||||
<h4>Format SDcard</h4>
|
||||
<div class="alert alert-danger">
|
||||
<h4>ATTENTION! Formatting will destroy all data on the SDcard.</h4>
|
||||
<p>Make sure you have a backup copy if you are going to use the data in the future.</p>
|
||||
<form action="<%= $SCRIPT_NAME %>" method="post">
|
||||
<% field_hidden "doFormatCard" "true" %>
|
||||
<% button_submit "Format SDcard" "danger" %>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<% fi %>
|
||||
<% fi %>
|
||||
|
||||
<%in p/footer.cgi %>
|
||||
Reference in New Issue
Block a user