init
This commit is contained in:
commit
b530498e0b
|
|
@ -0,0 +1,11 @@
|
|||
<?php include 'header.php'; ?>
|
||||
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<?php include 'footer.php'; ?>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,26 @@
|
|||
user www-data;
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
pid /run/nginx.pid;
|
||||
error_log /var/log/nginx/error.log;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens build;
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
access_log /var/log/nginx/access.log;
|
||||
gzip on;
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
// firewall-form-handler.php
|
||||
$jsonFile = __DIR__ . '/firewall.json';
|
||||
|
||||
// defaults
|
||||
$defaults = [
|
||||
'firewall' => 'disable',
|
||||
'ips' => ['', '', '', '', '']
|
||||
];
|
||||
|
||||
// load existing data
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
} else {
|
||||
$data = $defaults;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$saveSuccess = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// read posted values
|
||||
$posted_firewall = isset($_POST['firewall']) && in_array($_POST['firewall'], ['enable', 'disable']) ? $_POST['firewall'] : 'disable';
|
||||
$posted_ips = [];
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$key = "ip{$i}";
|
||||
$val = isset($_POST[$key]) ? trim((string)$_POST[$key]) : '';
|
||||
$posted_ips[] = $val;
|
||||
}
|
||||
|
||||
// validate IPs (allow empty)
|
||||
foreach ($posted_ips as $index => $ip) {
|
||||
if ($ip !== '' && !filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
$errors[] = "IP" . ($index + 1) . " is not a valid IP address: " . htmlspecialchars($ip);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$new = [
|
||||
'firewall' => $posted_firewall,
|
||||
'ips' => $posted_ips
|
||||
];
|
||||
$json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($jsonFile, $json, LOCK_EX) === false) {
|
||||
$errors[] = "Failed to write {$jsonFile}. Check permissions.";
|
||||
} else {
|
||||
$data = $new;
|
||||
$saveSuccess = "Saved.";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'header.php'; ?>
|
||||
<form method="POST" novalidate>
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
<h3>Firewall</h3>
|
||||
<br>
|
||||
<div class="input-container">
|
||||
<input type="radio" id="firewall_enable" name="firewall" value="enable" <?php if ($data['firewall'] === 'enable') echo 'checked'; ?>>
|
||||
<label for="firewall_enable">Enable</label><br>
|
||||
|
||||
<input type="radio" id="firewall_disable" name="firewall" value="disable" <?php if ($data['firewall'] === 'disable') echo 'checked'; ?>>
|
||||
<label for="firewall_disable">Disable</label><br>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ip1" name="ip1" placeholder="IP1" value="<?php echo htmlspecialchars($data['ips'][0] ?? ''); ?>">
|
||||
<label for="ip1">IP1</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ip2" name="ip2" placeholder="IP2" value="<?php echo htmlspecialchars($data['ips'][1] ?? ''); ?>">
|
||||
<label for="ip2">IP2</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ip3" name="ip3" placeholder="IP3" value="<?php echo htmlspecialchars($data['ips'][2] ?? ''); ?>">
|
||||
<label for="ip3">IP3</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ip4" name="ip4" placeholder="IP4" value="<?php echo htmlspecialchars($data['ips'][3] ?? ''); ?>">
|
||||
<label for="ip4">IP4</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ip5" name="ip5" placeholder="IP5" value="<?php echo htmlspecialchars($data['ips'][4] ?? ''); ?>">
|
||||
<label for="ip5">IP5</label>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; width:100%; margin-top:12px;">
|
||||
<button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
// status output
|
||||
if (!empty($errors)) {
|
||||
echo '<div style="color:#b00;text-align:center;margin-top:12px;">';
|
||||
foreach ($errors as $e) echo '<div>' . $e . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
if ($saveSuccess) {
|
||||
echo '<div style="color:green;text-align:center;margin-top:12px;">' . htmlspecialchars($saveSuccess) . '</div>';
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
include 'header.php';
|
||||
$url = "https://git.dbhatt.org/ShreeBhattJi/digital_encoder/raw/branch/main/version.json";
|
||||
|
||||
$json = file_get_contents($url);
|
||||
if ($json === false) {
|
||||
die("Failed to fetch JSON");
|
||||
}
|
||||
|
||||
// Decode
|
||||
$data = json_decode($json, true);
|
||||
if ($data === null) {
|
||||
die("Failed to decode JSON");
|
||||
}
|
||||
|
||||
// Access "version"
|
||||
if (isset($data['version'])) {
|
||||
$version = $data['version'];
|
||||
} else {
|
||||
$version = "Key 'version' not found";
|
||||
}
|
||||
|
||||
if ($_POST['action'] === 'update') {
|
||||
update_firmware();
|
||||
} elseif ($_POST['action'] === 'reset') {
|
||||
$files = glob('/var/www/html/*.json');
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
Currunt Firmware Version :- 1.0
|
||||
</div>
|
||||
<div class="card wide">
|
||||
Latest Firmware Version :- <?php echo $version ?>
|
||||
</div>
|
||||
<div class="card wide">
|
||||
<form method="post" class="form-center">
|
||||
<button type="submit" name="action" value="update" class="red-btn">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card wide">
|
||||
<form method="post" class="form-center" onsubmit="return confirm('Are you sure you want to reset all settings?');">
|
||||
<button type="submit" name="action" value="reset" class="red-btn">Reset</button>
|
||||
</form>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<footer class="site-footer">
|
||||
Crafted with ❤️ by ShreeBhattJi ( Devdatt Bhatt ) - Support +91-8000-74-1919
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
<?php include 'static.php'; ?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Full-page layout — static header & footer</title>
|
||||
<script src="chart.js"></script>
|
||||
<style>
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
:root {
|
||||
--header-h: 64px;
|
||||
--header-bg: linear-gradient(90deg, #1e293b, #0f172a);
|
||||
--header-color: #e6eef8;
|
||||
--footer-h: 52px;
|
||||
--footer-bg: linear-gradient(90deg, #1e293b, #0f172a);
|
||||
--footer-color: #e6eef8;
|
||||
}
|
||||
|
||||
main {
|
||||
height: calc(100vh - var(--header-h) - var(--footer-h));
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 16px;
|
||||
padding-bottom: calc(var(--footer-h) + 16px);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: 12px auto;
|
||||
padding: 12px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(2, 6, 23, 0.06);
|
||||
}
|
||||
|
||||
.containerindex {
|
||||
max-width: 1100px;
|
||||
margin: 12px auto;
|
||||
padding: 12px;
|
||||
padding-top: 63px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(2, 6, 23, 0.06);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1 1 43%;
|
||||
min-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.02));
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.card.wide {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.card .chart-wrap {
|
||||
flex: 1 1 auto;
|
||||
min-height: 180px;
|
||||
height: 247px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card canvas {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.status-row {
|
||||
margin-top: 12px;
|
||||
color: #9fb2d6;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
:root {
|
||||
--header-h: 56px;
|
||||
--footer-h: 56px;
|
||||
}
|
||||
|
||||
|
||||
main {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1 1 100%;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.card .chart-wrap {
|
||||
height: 220px;
|
||||
min-height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: var(--footer-h);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
background: var(--footer-bg);
|
||||
color: var(--footer-color);
|
||||
z-index: 999;
|
||||
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.18);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.site-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: var(--footer-h, 73px);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 48px;
|
||||
margin-bottom: 57px;
|
||||
background: linear-gradient(90deg, #0f172a, #1e293b);
|
||||
color: #e6eef8;
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.4px;
|
||||
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
|
||||
z-index: 999;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
|
||||
.site-header nav a {
|
||||
margin-left: 28px;
|
||||
color: #e6eef8;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.site-header nav a:hover {
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
.site-header.scrolled {
|
||||
background: rgba(15, 23, 42, 0.9);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 7px;
|
||||
}
|
||||
|
||||
.dropdown-label {
|
||||
font-size: 23px;
|
||||
font-weight: 500;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dropdown select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
color: black;
|
||||
padding: 12px 40px 12px 16px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown select:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.dropdown::after {
|
||||
content: "▼";
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dropdown select option {
|
||||
background: #ffffff;
|
||||
color: #1e293b;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
|
||||
.input-group {
|
||||
position: relative;
|
||||
width: auto;
|
||||
min-width: 333px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
width: 100%;
|
||||
padding: 11px 11px;
|
||||
font-size: 13px;
|
||||
border: 2px solid #cbd5e1;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
background: white;
|
||||
transition: border-color 0.3s ease;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.input-group input:focus {
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #64748b;
|
||||
font-size: 16px;
|
||||
pointer-events: none;
|
||||
transition: 0.3s ease all;
|
||||
background: white;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.input-group input:focus+label,
|
||||
.input-group input:not(:placeholder-shown)+label {
|
||||
top: -6px;
|
||||
left: 8px;
|
||||
font-size: 12px;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.checkbox-group input[type="checkbox"] {
|
||||
accent-color: #3b82f6;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-group label {
|
||||
font-size: 14px;
|
||||
color: #1e293b;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.red-btn {
|
||||
background-color: red;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
/* bold text */
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
width: 33%;
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.red-btn:hover {
|
||||
background-color: darkred;
|
||||
}
|
||||
|
||||
.form-center {
|
||||
text-align: center;
|
||||
/* center button */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header class="site-header">
|
||||
Encoder / Decoder
|
||||
<nav aria-label="Top navigation">
|
||||
<a href="index.php">Monitor</a>
|
||||
<a href="input.php">Input</a>
|
||||
<a href="output.php">Output</a>
|
||||
<a href="network.php">Network</a>
|
||||
<a href="firewall.php">Firewall</a>
|
||||
<a href="firmware.php">Firmware</a>
|
||||
<a href="about_us.php">About Us</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
<?php include 'header.php'; ?>
|
||||
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<h3>CPU (%)</h3>
|
||||
<div class="chart-wrap"><canvas id="cpuChart"></canvas></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>RAM (%)</h3>
|
||||
<div class="chart-wrap"><canvas id="ramChart"></canvas></div>
|
||||
</div>
|
||||
<div class="card wide">
|
||||
<h3>Network (KB/s)</h3>
|
||||
<div class="chart-wrap"><canvas id="netChart"></canvas></div>
|
||||
</div>
|
||||
<div class="card wide">
|
||||
<h3>Disk I/O (KB/s) & Disk %</h3>
|
||||
<div class="chart-wrap"><canvas id="diskChart"></canvas></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:12px; color:#9fb2d6; display:flex; justify-content:space-between;">
|
||||
<div>Last update: <span id="lastUpdate">—</span></div>
|
||||
<div>CPU: <span id="lastCpu">—</span>% · RAM: <span id="lastRam">—</span>% · In: <span id="lastIn">—</span>KB/s ·
|
||||
Out: <span id="lastOut">—</span>KB/s</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const POLL_MS = 1000;
|
||||
const JSON_URL = "metrics.json";
|
||||
|
||||
function toKB(v) {
|
||||
return Math.round(v / 1024);
|
||||
}
|
||||
|
||||
const cpuChart = new Chart(document.getElementById('cpuChart').getContext('2d'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'CPU %',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
min: 0,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const ramChart = new Chart(document.getElementById('ramChart').getContext('2d'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'RAM %',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
min: 0,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const netChart = new Chart(document.getElementById('netChart').getContext('2d'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Net In (KB/s)',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
},
|
||||
{
|
||||
label: 'Net Out (KB/s)',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const diskChart = new Chart(document.getElementById('diskChart').getContext('2d'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Disk Read (KB/s)',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
},
|
||||
{
|
||||
label: 'Disk Write (KB/s)',
|
||||
data: [],
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
},
|
||||
{
|
||||
label: 'Disk %',
|
||||
data: [],
|
||||
yAxisID: 'percent',
|
||||
fill: false,
|
||||
tension: 0.2
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
position: 'left',
|
||||
beginAtZero: true
|
||||
},
|
||||
percent: {
|
||||
position: 'right',
|
||||
min: 0,
|
||||
max: 100,
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
callback: v => v + '%'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function update() {
|
||||
try {
|
||||
const res = await fetch(JSON_URL + "?_=" + Date.now(), {
|
||||
cache: 'no-store'
|
||||
});
|
||||
if (!res.ok) throw new Error('fetch fail ' + res.status);
|
||||
const j = await res.json();
|
||||
|
||||
const labels = j.timestamps.map(t => new Date(t).toLocaleTimeString());
|
||||
cpuChart.data.labels = labels;
|
||||
cpuChart.data.datasets[0].data = j.cpu_percent;
|
||||
|
||||
ramChart.data.labels = labels;
|
||||
ramChart.data.datasets[0].data = j.ram_percent;
|
||||
|
||||
netChart.data.labels = labels;
|
||||
netChart.data.datasets[0].data = j.net_in_Bps.map(toKB);
|
||||
netChart.data.datasets[1].data = j.net_out_Bps.map(toKB);
|
||||
|
||||
diskChart.data.labels = labels;
|
||||
diskChart.data.datasets[0].data = j.disk_read_Bps.map(toKB);
|
||||
diskChart.data.datasets[1].data = j.disk_write_Bps.map(toKB);
|
||||
diskChart.data.datasets[2].data = j.disk_percent;
|
||||
|
||||
cpuChart.update();
|
||||
ramChart.update();
|
||||
netChart.update();
|
||||
diskChart.update();
|
||||
|
||||
const last = labels.length - 1;
|
||||
if (last >= 0) {
|
||||
document.getElementById('lastUpdate').textContent = labels[last];
|
||||
document.getElementById('lastCpu').textContent = j.cpu_percent[last];
|
||||
document.getElementById('lastRam').textContent = j.ram_percent[last];
|
||||
document.getElementById('lastIn').textContent = toKB(j.net_in_Bps[last]);
|
||||
document.getElementById('lastOut').textContent = toKB(j.net_out_Bps[last]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('update failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(update, POLL_MS);
|
||||
update();
|
||||
</script>
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"input": "rtmp",
|
||||
"hdmi": {
|
||||
"resolution": "1920x1080",
|
||||
"audio_source": "hw:1,0"
|
||||
},
|
||||
"url": "https://cdn.urmic.org/unavailable.mp4",
|
||||
"rtmp": {
|
||||
"mount": "mahadev",
|
||||
"password": "live",
|
||||
"port": "1935"
|
||||
},
|
||||
"srt": {
|
||||
"stream_id_1": "har",
|
||||
"stream_id_2": "har",
|
||||
"stream_id_3": "Mahadev",
|
||||
"port": "1937"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
<?php include 'header.php'; ?>
|
||||
<?php
|
||||
// path to JSON file
|
||||
$jsonFile = __DIR__ . '/input.json';
|
||||
|
||||
// load existing data or defaults
|
||||
$defaults = [
|
||||
'input' => 'url',
|
||||
'hdmi' => [
|
||||
'resolution' => '1920x1080',
|
||||
'audio_source' => 'hw:1,0'
|
||||
],
|
||||
'url' => 'https://cdn.urmic.org/unavailable.mp4',
|
||||
'rtmp' => [
|
||||
'mount' => '',
|
||||
'password' => 'live',
|
||||
'port' => '1935'
|
||||
],
|
||||
'srt' => [
|
||||
'stream_id_1' => 'har',
|
||||
'stream_id_2' => 'har',
|
||||
'stream_id_3' => 'Mahadev',
|
||||
'port' => '1937'
|
||||
]
|
||||
];
|
||||
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
} else {
|
||||
$data = $defaults;
|
||||
}
|
||||
|
||||
// handle form submit
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// simple sanitizer
|
||||
$posted = function ($k, $default = '') {
|
||||
return isset($_POST[$k]) ? trim((string)$_POST[$k]) : $default;
|
||||
};
|
||||
|
||||
$new = [
|
||||
'input' => $posted('input', $defaults['input']),
|
||||
'hdmi' => [
|
||||
'resolution' => $posted('hdmi_resolution', $defaults['hdmi']['resolution']),
|
||||
'audio_source' => $posted('hdmi_audio_source', $defaults['hdmi']['audio_source'])
|
||||
],
|
||||
'url' => $posted('url', $defaults['url']),
|
||||
'rtmp' => [
|
||||
'mount' => $posted('rtmp_mount', $defaults['rtmp']['mount']),
|
||||
'password' => $posted('rtmp_password', $defaults['rtmp']['password']),
|
||||
'port' => $posted('rtmp_port', $defaults['rtmp']['port'])
|
||||
],
|
||||
'srt' => [
|
||||
'stream_id_1' => $posted('srt_stream_id_1', $defaults['srt']['stream_id_1']),
|
||||
'stream_id_2' => $posted('srt_stream_id_2', $defaults['srt']['stream_id_2']),
|
||||
'stream_id_3' => $posted('srt_stream_id_3', $defaults['srt']['stream_id_3']),
|
||||
'port' => $posted('srt_port', $defaults['srt']['port'])
|
||||
]
|
||||
];
|
||||
|
||||
// write JSON with exclusive lock and pretty print
|
||||
$json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($jsonFile, $json, LOCK_EX) === false) {
|
||||
$saveError = "Failed to write $jsonFile. Check permissions.";
|
||||
} else {
|
||||
$data = $new; // reload into form
|
||||
$saveSuccess = "Saved.";
|
||||
}
|
||||
|
||||
update_service();
|
||||
}
|
||||
?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Input :</span>
|
||||
<div class="dropdown">
|
||||
<select name="input">
|
||||
<?php
|
||||
$opts = ['hdmi', 'url', 'rtmp', 'srt'];
|
||||
foreach ($opts as $o) {
|
||||
$sel = ($data['input'] === $o) ? 'selected' : '';
|
||||
echo "<option value=\"" . htmlspecialchars($o) . "\" $sel>" . htmlspecialchars($o) . "</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>HDMI Settings</h3>
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Resolution :</span>
|
||||
<div class="dropdown">
|
||||
<select name="hdmi_resolution">
|
||||
<?php
|
||||
$res = ['1920x1080', '1280x720', '720x576'];
|
||||
foreach ($res as $r) {
|
||||
$sel = ($data['hdmi']['resolution'] === $r) ? 'selected' : '';
|
||||
echo "<option value=\"" . htmlspecialchars($r) . "\" $sel>$r</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Audio Source :</span>
|
||||
<div class="dropdown">
|
||||
<select name="hdmi_audio_source">
|
||||
<?php
|
||||
$aopts = ['hw:0,0', 'hw:1,0'];
|
||||
foreach ($aopts as $a) {
|
||||
$sel = ($data['hdmi']['audio_source'] === $a) ? 'selected' : '';
|
||||
echo "<option value=\"" . htmlspecialchars($a) . "\" $sel>$a</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>URL Setting</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="url" name="url" value="<?php echo htmlspecialchars($data['url']); ?>" placeholder=" ">
|
||||
<label for="url">URL</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>RTMP Server Setting</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_mount" name="rtmp_mount" value="<?php echo htmlspecialchars($data['rtmp']['mount']); ?>" placeholder="Mount Name">
|
||||
<label for="rtmp_mount">Channel name</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_password" name="rtmp_password" value="<?php echo htmlspecialchars($data['rtmp']['password']); ?>" placeholder="live">
|
||||
<label for="rtmp_password">Password</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_port" name="rtmp_port" value="<?php echo htmlspecialchars($data['rtmp']['port']); ?>" placeholder="1935">
|
||||
<label for="rtmp_port">Port Number</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>SRT Caller Setting</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_stream_id_1" name="srt_stream_id_1" value="<?php echo htmlspecialchars($data['srt']['stream_id_1']); ?>" placeholder="pass1">
|
||||
<label for="srt_stream_id_1">Stream ID 1</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_stream_id_2" name="srt_stream_id_2" value="<?php echo htmlspecialchars($data['srt']['stream_id_2']); ?>" placeholder="pass2">
|
||||
<label for="srt_stream_id_2">Stream ID 2</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_stream_id_3" name="srt_stream_id_3" value="<?php echo htmlspecialchars($data['srt']['stream_id_3']); ?>" placeholder="pass3">
|
||||
<label for="srt_stream_id_3">Stream ID 3</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_port" name="srt_port" value="<?php echo htmlspecialchars($data['srt']['port']); ?>" placeholder="1937">
|
||||
<label for="srt_port">Port Number</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; width:100%; margin-top:12px;">
|
||||
<button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
</form>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<?php
|
||||
// optional status messages
|
||||
if (!empty($saveError)) echo '<p style="color:red;text-align:center;">' . htmlspecialchars($saveError) . '</p>';
|
||||
if (!empty($saveSuccess)) echo '<p style="color:green;text-align:center;">' . htmlspecialchars($saveSuccess) . '</p>';
|
||||
?>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1 @@
|
|||
ffmpeg -stream_loop -1 -re -i rtmp://127.0.0.1:1935/mahadev/live -vf "scale=1920x1080" -b:v 3.3M -minrate 3.3M -maxrate 3.3M -bufsize 3.3M -g 12 -c:a aac -ar 48000 -b:a 96k -f flv rtmp://127.0.0.1:1935/shree/bhattji
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
// network-form-handler.php
|
||||
$jsonFile = __DIR__ . '/network.json';
|
||||
$iface = trim(shell_exec("ip route get 1.1.1.1 | awk '{print $5; exit}'"));
|
||||
|
||||
$defaults = [
|
||||
'primary' => [
|
||||
'mode' => 'primary_dhcp', // primary_static or primary_dhcp
|
||||
'ip' => '',
|
||||
'subnet' => '',
|
||||
'gateway' => '',
|
||||
'vlan' => ''
|
||||
],
|
||||
'secondary' => [
|
||||
'mode' => 'secondary_disable', // secondary_static or secondary_dhcp
|
||||
'ip' => '',
|
||||
'subnet' => '',
|
||||
'gateway' => '',
|
||||
'vlan' => ''
|
||||
]
|
||||
];
|
||||
|
||||
// load existing
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
} else {
|
||||
$data = $defaults;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$success = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// helper
|
||||
$get = function ($k) {
|
||||
return isset($_POST[$k]) ? trim((string)$_POST[$k]) : '';
|
||||
};
|
||||
|
||||
$primary_mode = in_array($get('primary_mode'), ['primary_static', 'primary_dhcp']) ? $get('primary_mode') : 'primary_dhcp';
|
||||
$secondary_mode = in_array($get('secondary_mode'), ['secondary_static', 'secondary_dhcp','secondary_disable']) ? $get('secondary_mode') : 'secondary_dhcp';
|
||||
|
||||
$primary_ip = $get('network_primary_ip');
|
||||
$primary_subnet = $get('network_primary_subnet');
|
||||
$primary_gateway = $get('network_primary_gateway');
|
||||
$primary_vlan = $get('network_primary_vlan');
|
||||
|
||||
$secondary_ip = $get('network_secondary_ip');
|
||||
$secondary_subnet = $get('network_secondary_subnet');
|
||||
$secondary_gateway = $get('network_secondary_gateway');
|
||||
$secondary_vlan = $get('network_secondary_vlan');
|
||||
|
||||
// Validate IPs (allow empty). Subnet accepted as IP or CIDR like 192.168.1.0/24
|
||||
$validate_ip_or_cidr = function ($v) {
|
||||
if ($v === '') return true;
|
||||
if (strpos($v, '/') !== false) {
|
||||
[$ip, $cidr] = explode('/', $v, 2);
|
||||
return filter_var($ip, FILTER_VALIDATE_IP) !== false && ctype_digit($cidr) && (int)$cidr >= 0 && (int)$cidr <= 32;
|
||||
}
|
||||
return filter_var($v, FILTER_VALIDATE_IP) !== false;
|
||||
};
|
||||
|
||||
foreach (
|
||||
[
|
||||
['field' => 'Primary IP', 'value' => $primary_ip],
|
||||
['field' => 'Primary Subnet', 'value' => $primary_subnet],
|
||||
['field' => 'Primary Gateway', 'value' => $primary_gateway],
|
||||
['field' => 'Secondary IP', 'value' => $secondary_ip],
|
||||
['field' => 'Secondary Subnet', 'value' => $secondary_subnet],
|
||||
['field' => 'Secondary Gateway', 'value' => $secondary_gateway],
|
||||
] as $f
|
||||
) {
|
||||
if ($f['value'] !== '') {
|
||||
$ok = $f['field'] === 'Primary Subnet' || $f['field'] === 'Secondary Subnet'
|
||||
? $validate_ip_or_cidr($f['value'])
|
||||
: filter_var($f['value'], FILTER_VALIDATE_IP) !== false;
|
||||
if (!$ok) $errors[] = $f['field'] . ' is invalid: ' . htmlspecialchars($f['value']);
|
||||
}
|
||||
}
|
||||
|
||||
// VLAN numeric check (allow empty)
|
||||
foreach ([['Primary VLAN', $primary_vlan], ['Secondary VLAN', $secondary_vlan]] as $v) {
|
||||
if ($v[1] !== '' && (!ctype_digit($v[1]) || (int)$v[1] < 0 || (int)$v[1] > 4094)) {
|
||||
$errors[] = $v[0] . ' must be a number 0-4094';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$new = [
|
||||
'primary' => [
|
||||
'mode' => $primary_mode,
|
||||
'ip' => $primary_ip,
|
||||
'subnet' => $primary_subnet,
|
||||
'gateway' => $primary_gateway,
|
||||
'vlan' => $primary_vlan
|
||||
],
|
||||
'secondary' => [
|
||||
'mode' => $secondary_mode,
|
||||
'ip' => $secondary_ip,
|
||||
'subnet' => $secondary_subnet,
|
||||
'gateway' => $secondary_gateway,
|
||||
'vlan' => $secondary_vlan
|
||||
]
|
||||
];
|
||||
$json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($jsonFile, $json, LOCK_EX) === false) {
|
||||
$errors[] = "Failed to write {$jsonFile}. Check permissions.";
|
||||
} else {
|
||||
$data = $new;
|
||||
$success = 'Saved.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'header.php'; ?>
|
||||
<form method="POST" novalidate>
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
<h3>Primary Interface</h3>
|
||||
<br>
|
||||
<div class="input-container">
|
||||
<input type="radio" id="primary_static" name="primary_mode" value="primary_static" <?php if ($data['primary']['mode'] === 'primary_static') echo 'checked'; ?>>
|
||||
<label for="primary_static">STATIC</label><br>
|
||||
|
||||
<input type="radio" id="primary_dhcp" name="primary_mode" value="primary_dhcp" <?php if ($data['primary']['mode'] === 'primary_dhcp') echo 'checked'; ?>>
|
||||
<label for="primary_dhcp">DHCP</label><br>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_primary_ip" name="network_primary_ip" placeholder="Address" value="<?php echo htmlspecialchars($data['primary']['ip']); ?>">
|
||||
<label for="network_primary_ip">Address</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_primary_subnet" name="network_primary_subnet" placeholder="Subnet (e.g. 192.168.1.0/24)" value="<?php echo htmlspecialchars($data['primary']['subnet']); ?>">
|
||||
<label for="network_primary_subnet">Subnet</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_primary_gateway" name="network_primary_gateway" placeholder="Gateway" value="<?php echo htmlspecialchars($data['primary']['gateway']); ?>">
|
||||
<label for="network_primary_gateway">Gateway</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_primary_vlan" name="network_primary_vlan" placeholder="Vlan" value="<?php echo htmlspecialchars($data['primary']['vlan']); ?>">
|
||||
<label for="network_primary_vlan">Vlan</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>Secondary Vlan Interface</h3>
|
||||
<br>
|
||||
<div class="input-container">
|
||||
<input type="radio" id="secondary_static" name="secondary_mode" value="secondary_static" <?php if ($data['secondary']['mode'] === 'secondary_static') echo 'checked'; ?>>
|
||||
<label for="secondary_static">STATIC</label><br>
|
||||
|
||||
<input type="radio" id="secondary_dhcp" name="secondary_mode" value="secondary_dhcp" <?php if ($data['secondary']['mode'] === 'secondary_dhcp') echo 'checked'; ?>>
|
||||
<label for="secondary_dhcp">DHCP</label><br>
|
||||
|
||||
<input type="radio" id="secondary_disable" name="secondary_mode" value="secondary_disable" <?php if ($data['secondary']['mode'] === 'secondary_disable') echo 'checked'; ?>>
|
||||
<label for="secondary_disable">Disable</label><br>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_secondary_ip" name="network_secondary_ip" placeholder="Address" value="<?php echo htmlspecialchars($data['secondary']['ip']); ?>">
|
||||
<label for="network_secondary_ip">Address</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_secondary_subnet" name="network_secondary_subnet" placeholder="Subnet (e.g. 10.0.0.0/24)" value="<?php echo htmlspecialchars($data['secondary']['subnet']); ?>">
|
||||
<label for="network_secondary_subnet">Subnet</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_secondary_gateway" name="network_secondary_gateway" placeholder="Gateway" value="<?php echo htmlspecialchars($data['secondary']['gateway']); ?>">
|
||||
<label for="network_secondary_gateway">Gateway</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="network_secondary_vlan" name="network_secondary_vlan" placeholder="Vlan" value="<?php echo htmlspecialchars($data['secondary']['vlan']); ?>">
|
||||
<label for="network_secondary_vlan">Vlan</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; width:100%; margin-top:12px;">
|
||||
<button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
if (!empty($errors)) {
|
||||
echo '<div style="color:#b00;text-align:center;margin-top:12px;">';
|
||||
foreach ($errors as $e) echo '<div>' . $e . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
if ($success) {
|
||||
echo '<div style="color:green;text-align:center;margin-top:12px;">' . htmlspecialchars($success) . '</div>';
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
|
||||
rtmp {
|
||||
server {
|
||||
listen 1935;
|
||||
chunk_size 4096;
|
||||
|
||||
application mahadev {
|
||||
live on;
|
||||
drop_idle_publisher 10;
|
||||
idle_streams off;
|
||||
record off;
|
||||
meta off;
|
||||
wait_video on;
|
||||
allow publish all;
|
||||
deny play all;
|
||||
allow play 127.0.0.1;
|
||||
}
|
||||
|
||||
application shree {
|
||||
live on;
|
||||
drop_idle_publisher 10;
|
||||
idle_streams off;
|
||||
record off;
|
||||
meta off;
|
||||
wait_video on;
|
||||
deny publish all;
|
||||
allow publish 127.0.0.1;
|
||||
allow play all;
|
||||
|
||||
push rtmp://192.168.2.45/live/live1;
|
||||
push rtmp://192.168.2.45/live/live2;
|
||||
push rtmp://192.168.2.45/live/live3;
|
||||
push rtmp://192.168.2.45/live/live4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
gzip on;
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
{
|
||||
"output": "rtmp_multiple",
|
||||
"video": {
|
||||
"resolution": "1920x1080",
|
||||
"format": "h264",
|
||||
"data_rate": "3.3M",
|
||||
"gop": "12"
|
||||
},
|
||||
"audio": {
|
||||
"format": "aac",
|
||||
"sample_rate": "48000",
|
||||
"bit_rate": "96k"
|
||||
},
|
||||
"output_display": "1920x1080@60.00",
|
||||
"output_display_audio": "0,3",
|
||||
"rtmp_single": "",
|
||||
"srt_single": "",
|
||||
"rtmp_multiple": {
|
||||
"1": {
|
||||
"url": "rtmp://192.168.2.45/live/live1",
|
||||
"name": "facebook",
|
||||
"enabled": true
|
||||
},
|
||||
"2": {
|
||||
"url": "rtmp://192.168.2.45/live/live2",
|
||||
"name": "youtube.com",
|
||||
"enabled": true
|
||||
},
|
||||
"3": {
|
||||
"url": "rtmp://192.168.2.45/live/live3",
|
||||
"name": "urmic",
|
||||
"enabled": true
|
||||
},
|
||||
"4": {
|
||||
"url": "rtmp://192.168.2.45/live/live4",
|
||||
"name": "test4",
|
||||
"enabled": true
|
||||
},
|
||||
"5": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"6": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"7": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"8": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"9": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"10": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"11": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"srt_multiple": {
|
||||
"1": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"2": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"3": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"4": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"5": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"6": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"7": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"8": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"9": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"10": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
},
|
||||
"11": {
|
||||
"url": "",
|
||||
"name": "",
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"udp_primary": "",
|
||||
"udp_vlan": "",
|
||||
"custom_output": ""
|
||||
}
|
||||
|
|
@ -0,0 +1,382 @@
|
|||
<?php include 'header.php'; ?>
|
||||
<?php
|
||||
|
||||
$jsonFile = __DIR__ . '/output.json';
|
||||
|
||||
$defaults = [
|
||||
'output' => 'display',
|
||||
'video' => [
|
||||
'resolution' => '1920x1080',
|
||||
'format' => 'h264',
|
||||
'data_rate' => '3.3M',
|
||||
'gop' => '12'
|
||||
],
|
||||
'audio' => [
|
||||
'format' => 'aac',
|
||||
'sample_rate' => '48000',
|
||||
'bit_rate' => '96k'
|
||||
],
|
||||
'output_display' => '1920x1080@60.00',
|
||||
'output_display_audio' => '0,3',
|
||||
'rtmp_single' => '',
|
||||
'srt_single' => '',
|
||||
'rtmp_multiple' => [],
|
||||
'srt_multiple' => [],
|
||||
'udp_primary' => '',
|
||||
'udp_vlan' => '',
|
||||
'custom_output' => ''
|
||||
];
|
||||
|
||||
for ($i = 1; $i <= 11; $i++) {
|
||||
$defaults['rtmp_multiple'][$i] = ['url' => '', 'name' => '', 'enabled' => false];
|
||||
$defaults['srt_multiple'][$i] = ['url' => '', 'name' => '', 'enabled' => false];
|
||||
}
|
||||
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
|
||||
$data = array_replace_recursive($defaults, $data);
|
||||
} else {
|
||||
$data = $defaults;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$success = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
$get = function ($k, $d = '') {
|
||||
return isset($_POST[$k]) ? trim((string)$_POST[$k]) : $d;
|
||||
};
|
||||
|
||||
$new = $data;
|
||||
|
||||
$new['output'] = $get('output', $defaults['output']);
|
||||
|
||||
$new['video']['resolution'] = $get('output_resolution', $defaults['video']['resolution']);
|
||||
$new['video']['format'] = $get('output_video_formate', $defaults['video']['format']);
|
||||
$new['video']['data_rate'] = $get('output_data_rate', $defaults['video']['data_rate']);
|
||||
$new['video']['gop'] = $get('output_gop', $defaults['video']['gop']);
|
||||
|
||||
$new['audio']['format'] = $get('output_audio_formate', $defaults['audio']['format']);
|
||||
$new['audio']['sample_rate'] = $get('output_audio_sample_rate', $defaults['audio']['sample_rate']);
|
||||
$new['audio']['bit_rate'] = $get('output_audio_bit_rate', $defaults['audio']['bit_rate']);
|
||||
|
||||
$new['output_display'] = $get('output_display', $defaults['output_display']);
|
||||
$new['output_display_audio'] = $get('output_display_audio', $defaults['output_display_audio']);
|
||||
|
||||
|
||||
$new['rtmp_single'] = $get('rtmp_single', '');
|
||||
$new['srt_single'] = $get('srt_single', '');
|
||||
|
||||
$new['udp_primary'] = $get('udp_primary', '');
|
||||
$new['udp_vlan'] = $get('udp_vlan', '');
|
||||
$new['custom_output'] = $get('custom_output', '');
|
||||
|
||||
for ($i = 1; $i <= 11; $i++) {
|
||||
$u = $get("rtmp_{$i}", '');
|
||||
$n = $get("rtmp_{$i}_name", '');
|
||||
$e = isset($_POST["rtmp_{$i}_enable"]) ? true : false;
|
||||
$new['rtmp_multiple'][$i] = ['url' => $u, 'name' => $n, 'enabled' => $e];
|
||||
|
||||
$u2 = $get("srt_{$i}", '');
|
||||
$n2 = $get("srt_{$i}_name", '');
|
||||
$e2 = isset($_POST["srt_{$i}_enable"]) ? true : false;
|
||||
$new['srt_multiple'][$i] = ['url' => $u2, 'name' => $n2, 'enabled' => $e2];
|
||||
}
|
||||
|
||||
if ($new['video']['gop'] !== '' && !ctype_digit((string)$new['video']['gop'])) {
|
||||
$errors[] = "GOP must be an integer.";
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($jsonFile, $json, LOCK_EX) === false) {
|
||||
$errors[] = "Failed to write {$jsonFile}. Check permissions.";
|
||||
} else {
|
||||
$data = $new;
|
||||
$success = "Saved.";
|
||||
}
|
||||
}
|
||||
update_service();
|
||||
}
|
||||
?>
|
||||
<form method="POST">
|
||||
<div class="containerindex">
|
||||
<div class="grid">
|
||||
<div class="card wide">
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Output :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output" id="output">
|
||||
<option value="display" <?php if ($data['output'] == 'display') echo 'selected'; ?>>DISPLAY - HDMI - VGA</option>
|
||||
<option value="rtmp_single" <?php if ($data['output'] == 'rtmp_single') echo 'selected'; ?>>RTMP SINGLE</option>
|
||||
<option value="srt_single" <?php if ($data['output'] == 'srt_single') echo 'selected'; ?>>SRT SINGLE</option>
|
||||
<option value="rtmp_multiple" <?php if ($data['output'] == 'rtmp_multiple') echo 'selected'; ?>>RTMP MULTIPLE</option>
|
||||
<option value="srt_multiple" <?php if ($data['output'] == 'srt_multiple') echo 'selected'; ?>>SRT MULTIPLE</option>
|
||||
<option value="udp_primary" <?php if ($data['output'] == 'udp_primary') echo 'selected'; ?>>UDP PRIMARY INTERFACE</option>
|
||||
<option value="udp_vlan" <?php if ($data['output'] == 'udp_vlan') echo 'selected'; ?>>UDP VLAN INTERFACE</option>
|
||||
<option value="custom" <?php if ($data['output'] == 'custom') echo 'selected'; ?>>CUSTOM OUTPUT</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Video Setting</h3>
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Output Resolution :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output_resolution" id="output_resolution">
|
||||
<option value="720x480" <?php if ($data['video']['resolution'] == '720x480') echo 'selected'; ?>>480p 720x480 NTSC DVD</option>
|
||||
<option value="720x576" <?php if ($data['video']['resolution'] == '720x576') echo 'selected'; ?>>576p 720x576 PAL DVD</option>
|
||||
<option value="1280x720" <?php if ($data['video']['resolution'] == '1280x720') echo 'selected'; ?>>720p 1280x720 HD</option>
|
||||
<option value="1920x1080" <?php if ($data['video']['resolution'] == '1920x1080') echo 'selected'; ?>>1080p 1920x1080 FHD</option>
|
||||
<option value="2560x1440" <?php if ($data['video']['resolution'] == '2560x1440') echo 'selected'; ?>>2k 2560x1440 QHD</option>
|
||||
<option value="2048x1080" <?php if ($data['video']['resolution'] == '2048x1080') echo 'selected'; ?>>2k 2048x1080 DCI 2K</option>
|
||||
<option value="3840x2160" <?php if ($data['video']['resolution'] == '3840x2160') echo 'selected'; ?>>4k 3840x2160 UHD</option>
|
||||
<option value="4096x2160" <?php if ($data['video']['resolution'] == '4096x2160') echo 'selected'; ?>>4k 4096x2160 DCI 4K</option>
|
||||
<option value="7680x4320" <?php if ($data['video']['resolution'] == '7680x4320') echo 'selected'; ?>>8k 7680x4320 UHD 8K</option>
|
||||
<option value="8192x4320" <?php if ($data['video']['resolution'] == '8192x4320') echo 'selected'; ?>>8k 8192x4320 DCI 8K</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Output Video Formate :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output_video_formate" id="output_video_formate">
|
||||
<option value="mpeg2" <?php if ($data['video']['format'] == 'mpeg2') echo 'selected'; ?>>mpeg2</option>
|
||||
<option value="mpeg4" <?php if ($data['video']['format'] == 'mpeg4') echo 'selected'; ?>>mpeg4</option>
|
||||
<option value="h264" <?php if ($data['video']['format'] == 'h264') echo 'selected'; ?>>h264</option>
|
||||
<option value="h265" <?php if ($data['video']['format'] == 'h265') echo 'selected'; ?>>h265</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="output_data_rate" name="output_data_rate" placeholder="4M" value="<?php echo htmlspecialchars($data['video']['data_rate']); ?>">
|
||||
<label for="output_data_rate">OutPut Data Rate :</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="output_gop" name="output_gop" placeholder="12" value="<?php echo htmlspecialchars($data['video']['gop']); ?>">
|
||||
<label for="output_gop">GOP :</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Audio Setting</h3>
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Output Audio Formate :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output_audio_formate" id="output_audio_formate">
|
||||
<option value="mp2" <?php if ($data['audio']['format'] == 'mp2') echo 'selected'; ?>>mp2</option>
|
||||
<option value="mp3" <?php if ($data['audio']['format'] == 'mp3') echo 'selected'; ?>>mp3</option>
|
||||
<option value="aac" <?php if ($data['audio']['format'] == 'aac') echo 'selected'; ?>>aac</option>
|
||||
<option value="ac3" <?php if ($data['audio']['format'] == 'ac3') echo 'selected'; ?>>ac3</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="output_audio_sample_rate" name="output_audio_sample_rate" placeholder="48000" value="<?php echo htmlspecialchars($data['audio']['sample_rate']); ?>">
|
||||
<label for="output_audio_sample_rate">Sample Rate :</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="output_audio_bit_rate" name="output_audio_bit_rate" placeholder="96k" value="<?php echo htmlspecialchars($data['audio']['bit_rate']); ?>">
|
||||
<label for="output_audio_bit_rate">Bit Rate :</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>DISPLAY - HDMI - VGA</h3>
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Video Size :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output_display" id="output_display">
|
||||
<!-- 4K (4096x2160p) -->
|
||||
<option value="4096x2160@23.98" <?php if ($data['output_display'] == '4096x2160@23.98') echo 'selected'; ?>>4096x2160@23.98</option>
|
||||
<option value="4096x2160@24.00" <?php if ($data['output_display'] == '4096x2160@24.00') echo 'selected'; ?>>4096x2160@24.00</option>
|
||||
<option value="4096x2160@25.00" <?php if ($data['output_display'] == '4096x2160@25.00') echo 'selected'; ?>>4096x2160@25.00</option>
|
||||
<option value="4096x2160@29.97" <?php if ($data['output_display'] == '4096x2160@29.97') echo 'selected'; ?>>4096x2160@29.97</option>
|
||||
<option value="4096x2160@30.00" <?php if ($data['output_display'] == '4096x2160@30.00') echo 'selected'; ?>>4096x2160@30.00</option>
|
||||
<option value="4096x2160@47.95" <?php if ($data['output_display'] == '4096x2160@47.95') echo 'selected'; ?>>4096x2160@47.95</option>
|
||||
<option value="4096x2160@48.00" <?php if ($data['output_display'] == '4096x2160@48.00') echo 'selected'; ?>>4096x2160@48.00</option>
|
||||
<option value="4096x2160@50.00" <?php if ($data['output_display'] == '4096x2160@50.00') echo 'selected'; ?>>4096x2160@50.00</option>
|
||||
<option value="4096x2160@59.94" <?php if ($data['output_display'] == '4096x2160@59.94') echo 'selected'; ?>>4096x2160@59.94</option>
|
||||
<option value="4096x2160@60.00" <?php if ($data['output_display'] == '4096x2160@60.00') echo 'selected'; ?>>4096x2160@60.00</option>
|
||||
|
||||
<!-- UltraHD (3840x2160p) -->
|
||||
<option value="3840x2160@23.98" <?php if ($data['output_display'] == '3840x2160@23.98') echo 'selected'; ?>>3840x2160@23.98</option>
|
||||
<option value="3840x2160@24.00" <?php if ($data['output_display'] == '3840x2160@24.00') echo 'selected'; ?>>3840x2160@24.00</option>
|
||||
<option value="3840x2160@25.00" <?php if ($data['output_display'] == '3840x2160@25.00') echo 'selected'; ?>>3840x2160@25.00</option>
|
||||
<option value="3840x2160@29.97" <?php if ($data['output_display'] == '3840x2160@29.97') echo 'selected'; ?>>3840x2160@29.97</option>
|
||||
<option value="3840x2160@30.00" <?php if ($data['output_display'] == '3840x2160@30.00') echo 'selected'; ?>>3840x2160@30.00</option>
|
||||
<option value="3840x2160@50.00" <?php if ($data['output_display'] == '3840x2160@50.00') echo 'selected'; ?>>3840x2160@50.00</option>
|
||||
<option value="3840x2160@59.94" <?php if ($data['output_display'] == '3840x2160@59.94') echo 'selected'; ?>>3840x2160@59.94</option>
|
||||
<option value="3840x2160@60.00" <?php if ($data['output_display'] == '3840x2160@60.00') echo 'selected'; ?>>3840x2160@60.00</option>
|
||||
|
||||
<!-- 2K (2048x1080p) -->
|
||||
<option value="2048x1080@23.98" <?php if ($data['output_display'] == '2048x1080@23.98') echo 'selected'; ?>>2048x1080@23.98</option>
|
||||
<option value="2048x1080@24.00" <?php if ($data['output_display'] == '2048x1080@24.00') echo 'selected'; ?>>2048x1080@24.00</option>
|
||||
<option value="2048x1080@25.00" <?php if ($data['output_display'] == '2048x1080@25.00') echo 'selected'; ?>>2048x1080@25.00</option>
|
||||
<option value="2048x1080@29.97" <?php if ($data['output_display'] == '2048x1080@29.97') echo 'selected'; ?>>2048x1080@29.97</option>
|
||||
<option value="2048x1080@30.00" <?php if ($data['output_display'] == '2048x1080@30.00') echo 'selected'; ?>>2048x1080@30.00</option>
|
||||
<option value="2048x1080@47.95" <?php if ($data['output_display'] == '2048x1080@47.95') echo 'selected'; ?>>2048x1080@47.95</option>
|
||||
<option value="2048x1080@48.00" <?php if ($data['output_display'] == '2048x1080@48.00') echo 'selected'; ?>>2048x1080@48.00</option>
|
||||
<option value="2048x1080@50.00" <?php if ($data['output_display'] == '2048x1080@50.00') echo 'selected'; ?>>2048x1080@50.00</option>
|
||||
<option value="2048x1080@59.94" <?php if ($data['output_display'] == '2048x1080@59.94') echo 'selected'; ?>>2048x1080@59.94</option>
|
||||
<option value="2048x1080@60.00" <?php if ($data['output_display'] == '2048x1080@60.00') echo 'selected'; ?>>2048x1080@60.00</option>
|
||||
|
||||
<!-- HD (1920x1080p) -->
|
||||
<option value="1920x1080@23.98" <?php if ($data['output_display'] == '1920x1080@23.98') echo 'selected'; ?>>1920x1080@23.98</option>
|
||||
<option value="1920x1080@24.00" <?php if ($data['output_display'] == '1920x1080@24.00') echo 'selected'; ?>>1920x1080@24.00</option>
|
||||
<option value="1920x1080@25.00" <?php if ($data['output_display'] == '1920x1080@25.00') echo 'selected'; ?>>1920x1080@25.00</option>
|
||||
<option value="1920x1080@29.97" <?php if ($data['output_display'] == '1920x1080@29.97') echo 'selected'; ?>>1920x1080@29.97</option>
|
||||
<option value="1920x1080@30.00" <?php if ($data['output_display'] == '1920x1080@30.00') echo 'selected'; ?>>1920x1080@30.00</option>
|
||||
<option value="1920x1080@50.00" <?php if ($data['output_display'] == '1920x1080@50.00') echo 'selected'; ?>>1920x1080@50.00</option>
|
||||
<option value="1920x1080@59.94" <?php if ($data['output_display'] == '1920x1080@59.94') echo 'selected'; ?>>1920x1080@59.94</option>
|
||||
<option value="1920x1080@60.00" <?php if ($data['output_display'] == '1920x1080@60.00') echo 'selected'; ?>>1920x1080@60.00</option>
|
||||
|
||||
<!-- HD Interlaced (1920x1080i) -->
|
||||
<option value="1920x1080i@50.00" <?php if ($data['output_display'] == '1920x1080i@50.00') echo 'selected'; ?>>1920x1080i@50.00</option>
|
||||
<option value="1920x1080i@59.94" <?php if ($data['output_display'] == '1920x1080i@59.94') echo 'selected'; ?>>1920x1080i@59.94</option>
|
||||
<option value="1920x1080i@60.00" <?php if ($data['output_display'] == '1920x1080i@60.00') echo 'selected'; ?>>1920x1080i@60.00</option>
|
||||
|
||||
<!-- HD (1280x720p) -->
|
||||
<option value="1280x720@50.00" <?php if ($data['output_display'] == '1280x720@50.00') echo 'selected'; ?>>1280x720@50.00</option>
|
||||
<option value="1280x720@59.94" <?php if ($data['output_display'] == '1280x720@59.94') echo 'selected'; ?>>1280x720@59.94</option>
|
||||
<option value="1280x720@60.00" <?php if ($data['output_display'] == '1280x720@60.00') echo 'selected'; ?>>1280x720@60.00</option>
|
||||
|
||||
<!-- SD Progressive -->
|
||||
<option value="720x576@50.00" <?php if ($data['output_display'] == '720x576@50.00') echo 'selected'; ?>>720x576@50.00</option>
|
||||
<option value="720x480@59.94" <?php if ($data['output_display'] == '720x480@59.94') echo 'selected'; ?>>720x480@59.94</option>
|
||||
|
||||
<!-- SD Interlaced -->
|
||||
<option value="720x576i@25.00" <?php if ($data['output_display'] == '720x576i@25.00') echo 'selected'; ?>>720x576i@25.00</option>
|
||||
<option value="720x480i@29.97" <?php if ($data['output_display'] == '720x480i@29.97') echo 'selected'; ?>>720x480i@29.97</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-container">
|
||||
<span class="dropdown-label">Audio Output :</span>
|
||||
<div class="dropdown">
|
||||
<select name="output_display_audio" id="output_display_audio">
|
||||
<option value="0,0" <?php if ($data['output_display_audio'] == '0,0') echo 'selected'; ?>>0,0</option>
|
||||
<option value="0,1" <?php if ($data['output_display_audio'] == '0,1') echo 'selected'; ?>>0,1</option>
|
||||
<option value="0,2" <?php if ($data['output_display_audio'] == '0,2') echo 'selected'; ?>>0,2</option>
|
||||
<option value="0,3" <?php if ($data['output_display_audio'] == '0,3') echo 'selected'; ?>>0,3</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>RTMP SINGLE</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_single" name="rtmp_single" placeholder="rtmp" value="<?php echo htmlspecialchars($data['rtmp_single']); ?>">
|
||||
<label for="rtmp_single">RTMP URL</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>SRT SINGLE</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_single" name="srt_single" placeholder=" " value="<?php echo htmlspecialchars($data['srt_single']); ?>">
|
||||
<label for="srt_single">URL</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>RTMP MULTIPLE OUTPUT</h3>
|
||||
|
||||
<?php for ($i = 1; $i <= 11; $i++):
|
||||
$r = $data['rtmp_multiple'][$i];
|
||||
?>
|
||||
<div class="input-container">
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_<?php echo $i; ?>" name="rtmp_<?php echo $i; ?>" placeholder="rtmp" value="<?php echo htmlspecialchars($r['url']); ?>">
|
||||
<label for="rtmp_<?php echo $i; ?>">RTMP URL <?php echo $i; ?></label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="rtmp_<?php echo $i; ?>_name" name="rtmp_<?php echo $i; ?>_name" placeholder="Rtmp Name <?php echo $i; ?>" value="<?php echo htmlspecialchars($r['name']); ?>">
|
||||
<label for="rtmp_<?php echo $i; ?>_name">Rtmp Name <?php echo $i; ?></label>
|
||||
</div>
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="rtmp_<?php echo $i; ?>_enable" name="rtmp_<?php echo $i; ?>_enable" <?php if (!empty($r['enabled'])) echo 'checked'; ?>>
|
||||
<label for="rtmp_<?php echo $i; ?>_enable">Enable or Disable</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>SRT MULTIPLE OUTPUT</h3>
|
||||
|
||||
<?php for ($i = 1; $i <= 11; $i++):
|
||||
$s = $data['srt_multiple'][$i];
|
||||
?>
|
||||
<div class="input-container">
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_<?php echo $i; ?>" name="srt_<?php echo $i; ?>" placeholder="srt" value="<?php echo htmlspecialchars($s['url']); ?>">
|
||||
<label for="srt_<?php echo $i; ?>">SRT URL <?php echo $i; ?></label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" id="srt_<?php echo $i; ?>_name" name="srt_<?php echo $i; ?>_name" placeholder="Srt Name <?php echo $i; ?>" value="<?php echo htmlspecialchars($s['name']); ?>">
|
||||
<label for="srt_<?php echo $i; ?>_name">SRT Name <?php echo $i; ?></label>
|
||||
</div>
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="srt_<?php echo $i; ?>_enable" name="srt_<?php echo $i; ?>_enable" <?php if (!empty($s['enabled'])) echo 'checked'; ?>>
|
||||
<label for="srt_<?php echo $i; ?>_enable">Enable or Disable</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>UDP PRIMARY INTERFACE</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="udp_primary" name="udp_primary" placeholder="udp" value="<?php echo htmlspecialchars($data['udp_primary']); ?>">
|
||||
<label for="udp_primary">UDP Primary URL</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>UDP VLAN INTERFACE</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="udp_vlan" name="udp_vlan" placeholder="udp" value="<?php echo htmlspecialchars($data['udp_vlan']); ?>">
|
||||
<label for="udp_vlan">UDP VLAN URL</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card wide">
|
||||
<h3>CUSTOM OUTPUT</h3>
|
||||
<div class="input-group">
|
||||
<input type="text" id="custom_output" name="custom_output" placeholder="custom" value="<?php echo htmlspecialchars($data['custom_output']); ?>">
|
||||
<label for="custom_output">Custom Output</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; width:100%; margin-top:12px;">
|
||||
<button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button>
|
||||
</div>
|
||||
<br><br><br>
|
||||
|
||||
</form>
|
||||
|
||||
<?php
|
||||
if (!empty($errors)) {
|
||||
echo '<div style="color:#b00;text-align:center;margin-top:12px;">';
|
||||
foreach ($errors as $e) echo '<div>' . htmlspecialchars($e) . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
if ($success) {
|
||||
echo '<div style="color:green;text-align:center;margin-top:12px;">' . htmlspecialchars($success) . '</div>';
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
<?php
|
||||
|
||||
$nginx_top = "
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
$nginx_bottom = "
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
gzip on;
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
|
||||
}
|
||||
";
|
||||
|
||||
#sls.conf
|
||||
$sls = "
|
||||
srt {
|
||||
|
||||
worker_threads 64;
|
||||
worker_connections 500;
|
||||
|
||||
log_file /tmp/logs/error.log ;
|
||||
log_level info;
|
||||
|
||||
server {
|
||||
listen 1937;
|
||||
latency 1000; #ms
|
||||
|
||||
domain_player srt.urmic.org;
|
||||
domain_publisher pass1pass1pass1;
|
||||
backlog 100;
|
||||
idle_streams_timeout 10;#s -1: unlimited
|
||||
app {
|
||||
app_player onshreeganeshaynamah ;
|
||||
app_publisher pass2pass2pass2 ;
|
||||
|
||||
record_hls off;#on, off
|
||||
record_hls_segment_duration 10; #unit s
|
||||
|
||||
#relay {
|
||||
# type push;
|
||||
# mode all; #all; hash
|
||||
# reconnect_interval 10;
|
||||
# idle_streams_timeout 10;#s -1: unlimited
|
||||
# upstreams 192.168.31.106:8080?streamid=uplive.sls.com/live ;
|
||||
#}
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
function update_service()
|
||||
{
|
||||
|
||||
$candidate = '/var/www/html/nginx.conf';
|
||||
$fallback = '/var/www/html/default_nginx.conf';
|
||||
$target = '/etc/nginx/nginx.conf';
|
||||
|
||||
$cp_cmd = function (string $src, string $dst): string {
|
||||
return 'sudo /bin/cp ' . escapeshellarg($src) . ' ' . escapeshellarg($dst);
|
||||
};
|
||||
|
||||
$test_cmd = 'sudo /usr/sbin/nginx -t -q';
|
||||
$restart_cmd = 'sudo /bin/systemctl restart nginx';
|
||||
|
||||
|
||||
$input = "ffmpeg ";
|
||||
$input_link = "";
|
||||
$input_source = "";
|
||||
$input_rtmp_port = "";
|
||||
$input_port_srt = "";
|
||||
$input_rtmp_mount = "";
|
||||
$input_rtmp_pass = "";
|
||||
$output = "";
|
||||
global $nginx_top;
|
||||
global $nginx_bottom;
|
||||
$rtmp_multiple[] = [];
|
||||
$srt_multiple[] = [];
|
||||
$defaults = [
|
||||
'input' => 'url',
|
||||
'hdmi' => [
|
||||
'resolution' => '1920x1080',
|
||||
'audio_source' => 'hw:1,0'
|
||||
],
|
||||
'url' => 'https://cdn.urmic.org/unavailable.mp4',
|
||||
'rtmp' => [
|
||||
'mount' => '',
|
||||
'password' => 'live',
|
||||
'port' => '1935'
|
||||
],
|
||||
'srt' => [
|
||||
'stream_id_1' => 'har',
|
||||
'stream_id_2' => 'har',
|
||||
'stream_id_3' => 'Mahadev',
|
||||
'port' => '1937'
|
||||
]
|
||||
];
|
||||
|
||||
$jsonFile = __DIR__ . '/input.json';
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
}
|
||||
|
||||
$input_source = $data['input'];
|
||||
$input_rtmp_port = $data['rtmp']['port'];
|
||||
$input_rtmp_mount = $data['rtmp']['mount'];
|
||||
$input_rtmp_pass = $data['rtmp']['password'];
|
||||
$input_port_srt = $data['srt']['port'];
|
||||
|
||||
if ($input_rtmp_port === "80" || $input_rtmp_port === "443" || $input_port_srt === "80" || $input_port_srt === "443") {
|
||||
echo '<script>alert("80 or 443 port is not allowed .");</script>';
|
||||
die();
|
||||
}
|
||||
|
||||
switch ($input_source) {
|
||||
case "hdmi":
|
||||
$input .= "-f v4l2 -input_format mjpeg -framerate 30 -video_size " . $data['hdmi']['resolution'] . " -i /dev/video0 -f alsa -i " . $data['hdmi']['audio_source'];
|
||||
break;
|
||||
case "url":
|
||||
$input .= "-stream_loop -1 -re -i " . $data['url'];
|
||||
$input_link = $data['url'];
|
||||
break;
|
||||
case "rtmp":
|
||||
$input .= "-stream_loop -1 -re -i rtmp://127.0.0.1:" . $data['rtmp']['port'] . "/" . $data['rtmp']['mount'] . "/" . $data['rtmp']['password'];
|
||||
$input_link = "rtmp://127.0.0.1:" . $data['rtmp']['port'] . "/" . $data['rtmp']['mount'] . "/" . $data['rtmp']['password'];
|
||||
break;
|
||||
case "srt":
|
||||
$input .= "-stream_loop -1 -re -i srt://127.0.0.1:" . $data['srt']['port'] . "/" . $data['srt']['stream_id_1'] . "/" . $data['srt']['stream_id_2'] . "/" . $data['srt']['stream_id_3'];
|
||||
$input_link = "srt://127.0.0.1:" . $data['srt']['port'] . "/" . $data['srt']['stream_id_1'] . "/" . $data['srt']['stream_id_2'] . "/" . $data['srt']['stream_id_3'];
|
||||
$input_port_srt = $data['srt']['port'];
|
||||
break;
|
||||
}
|
||||
$input .= " ";
|
||||
|
||||
$jsonFile = __DIR__ . '/output.json';
|
||||
|
||||
// default structure
|
||||
$defaults = [
|
||||
'output' => 'display',
|
||||
'video' => [
|
||||
'resolution' => '1920x1080',
|
||||
'format' => 'h264',
|
||||
'data_rate' => '4M',
|
||||
'gop' => '12'
|
||||
],
|
||||
'audio' => [
|
||||
'format' => 'aac',
|
||||
'sample_rate' => '48000',
|
||||
'bit_rate' => '96k'
|
||||
],
|
||||
'output_display' => '1920x1080@60.00',
|
||||
'output_display_audio' => '0,3',
|
||||
'rtmp_single' => '',
|
||||
'srt_single' => '',
|
||||
'rtmp_multiple' => [],
|
||||
'srt_multiple' => [],
|
||||
'udp_primary' => '',
|
||||
'udp_vlan' => '',
|
||||
'custom_output' => ''
|
||||
];
|
||||
|
||||
for ($i = 1; $i <= 11; $i++) {
|
||||
$defaults['rtmp_multiple'][$i] = ['url' => '', 'name' => '', 'enabled' => false];
|
||||
$defaults['srt_multiple'][$i] = ['url' => '', 'name' => '', 'enabled' => false];
|
||||
}
|
||||
|
||||
if (file_exists($jsonFile)) {
|
||||
$raw = file_get_contents($jsonFile);
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) $data = $defaults;
|
||||
$data = array_replace_recursive($defaults, $data);
|
||||
} else {
|
||||
$data = $defaults;
|
||||
}
|
||||
|
||||
$rtmp_multiple = $data['rtmp_multiple'];
|
||||
$srt_multiple = $data['srt_multiple'];
|
||||
$output = $data['output'];
|
||||
|
||||
|
||||
|
||||
switch ($data['output']) {
|
||||
case "display":
|
||||
if ($input_source === "hdmi") {
|
||||
echo "<script>alert('HDMI input and Disply Output is not supported');</script>";
|
||||
} else {
|
||||
$output_display_audio = $data['output_display_audio'];
|
||||
$input = "mpv --fs --loop --hwdec=auto --audio-device=alsa/plughw:" . $output_display_audio . " " . $input_link;
|
||||
}
|
||||
break;
|
||||
case "rtmp_single":
|
||||
$input .= '-vf "scale=' . $data['video']['resolution'] . '" -b:v ' . $data['video']['data_rate']
|
||||
. ' -minrate ' . $data['video']['data_rate'] . ' -maxrate ' . $data['video']['data_rate'] . ' -bufsize ' . $data['video']['data_rate'] . ' -g ' . $data['video']['gop'] .
|
||||
' -c:a ' . $data['audio']['format'] . ' -ar ' . $data['audio']['sample_rate'] . ' -b:a ' . $data['audio']['bit_rate'] . ' -f flv ' . $data['rtmp_single'];
|
||||
break;
|
||||
case "srt_single":
|
||||
$input .= '-vf "scale=' . $data['video']['resolution'] . '" -b:v ' . $data['video']['data_rate'] . ' -minrate ' . $data['video']['data_rate'] . ' -maxrate ' . $data['video']['data_rate'] . ' -bufsize ' . $data['video']['data_rate'] . ' -g ' . $data['video']['gop'] .
|
||||
' -c:a ' . $data['audio']['format'] . ' -ar ' . $data['audio']['sample_rate'] . ' -b:a ' . $data['audio']['bit_rate'] . ' -f mpegts ' . $data['srt_single'];
|
||||
break;
|
||||
case "rtmp_multiple":
|
||||
$input .= '-vf "scale=' . $data['video']['resolution'] . '" -b:v ' . $data['video']['data_rate']
|
||||
. ' -minrate ' . $data['video']['data_rate'] . ' -maxrate ' . $data['video']['data_rate'] . ' -bufsize ' . $data['video']['data_rate'] . ' -g ' . $data['video']['gop'] .
|
||||
' -c:a ' . $data['audio']['format'] . ' -ar ' . $data['audio']['sample_rate'] . ' -b:a ' . $data['audio']['bit_rate'] . ' -f flv rtmp://127.0.0.1:'
|
||||
. $input_rtmp_port . '/shree/bhattji';
|
||||
break;
|
||||
case "srt_multiple":
|
||||
if (empty($input_port))
|
||||
$input_port = "1937";
|
||||
$input .= '-vf "scale=' . $data['video']['resolution'] . '" -b:v ' . $data['video']['data_rate']
|
||||
. ' -minrate ' . $data['video']['data_rate'] . ' -maxrate ' . $data['video']['data_rate'] . ' -bufsize ' . $data['video']['data_rate'] . ' -g ' . $data['video']['gop'] .
|
||||
' -c:a ' . $data['audio']['format'] . ' -ar ' . $data['audio']['sample_rate'] . ' -b:a ' . $data['audio']['bit_rate'] . ' -f mpegts srt://127.0.0.1:'
|
||||
. $input_port . '/shree/bhatt/ji';
|
||||
break;
|
||||
case "udp_primary":
|
||||
break;
|
||||
case "udp_vlan":
|
||||
break;
|
||||
case "custom_output":
|
||||
break;
|
||||
}
|
||||
|
||||
$service = $input;
|
||||
$file = "/var/www/html/main-encoder.sh";
|
||||
if (file_put_contents($file, $service) !== false) {
|
||||
echo "File saved.";
|
||||
} else {
|
||||
echo "Error writing file.";
|
||||
}
|
||||
|
||||
if (empty($input_rtmp_port))
|
||||
$input_rtmp_port = "1935";
|
||||
|
||||
$rtmp_push = "";
|
||||
|
||||
for ($i = 1; $i <= 11; $i++) {
|
||||
if ($rtmp_multiple[$i]['enabled'] == 1) {
|
||||
$rtmp_push .= "
|
||||
push " . $rtmp_multiple[$i]['url'] . ";";
|
||||
}
|
||||
}
|
||||
|
||||
$nginx = $nginx_top;
|
||||
if ($input_source === "rtmp") {
|
||||
$nginx .= "
|
||||
rtmp {
|
||||
server {
|
||||
listen " . $input_rtmp_port . ";
|
||||
chunk_size 4096;
|
||||
|
||||
application " . $input_rtmp_mount . " {
|
||||
live on;
|
||||
drop_idle_publisher 10;
|
||||
idle_streams off;
|
||||
record off;
|
||||
meta off;
|
||||
wait_video on;
|
||||
allow publish all;
|
||||
deny play all;
|
||||
allow play 127.0.0.1;
|
||||
}
|
||||
|
||||
application shree {
|
||||
live on;
|
||||
drop_idle_publisher 10;
|
||||
idle_streams off;
|
||||
record off;
|
||||
meta off;
|
||||
wait_video on;
|
||||
deny publish all;
|
||||
allow publish 127.0.0.1;
|
||||
allow play all;
|
||||
" .
|
||||
$rtmp_push
|
||||
. "
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
} else {
|
||||
$nginx .= "
|
||||
rtmp {
|
||||
server {
|
||||
listen 1935;
|
||||
chunk_size 4096;
|
||||
|
||||
application shree {
|
||||
live on;
|
||||
drop_idle_publisher 10;
|
||||
idle_streams off;
|
||||
record off;
|
||||
meta off;
|
||||
wait_video on;
|
||||
deny publish all;
|
||||
allow publish 127.0.0.1;
|
||||
allow play all;
|
||||
" .
|
||||
$rtmp_push
|
||||
. "
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
$nginx .= $nginx_bottom;
|
||||
$file = "/var/www/html/nginx.conf";
|
||||
if (file_put_contents($file, $nginx) !== false) {
|
||||
echo "File saved.";
|
||||
} else {
|
||||
echo "Error writing file.";
|
||||
}
|
||||
|
||||
exec($cp_cmd($candidate, $target), $out, $rc);
|
||||
// if nginx config test OK, restart and exit
|
||||
exec($test_cmd, $out, $rc);
|
||||
if ($rc === 0) {
|
||||
exec($restart_cmd, $out, $rc2);
|
||||
return;
|
||||
}
|
||||
|
||||
// fallback copy
|
||||
exec($cp_cmd($fallback, $target), $out, $rc);
|
||||
exec($test_cmd, $out, $rc);
|
||||
if ($rc === 0) {
|
||||
exec($restart_cmd, $out, $rc2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update_firewall() {}
|
||||
|
||||
function update_network() {}
|
||||
|
||||
function update_firmware() {}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
sudo mkdir /etc/srt;
|
||||
sudo apt update
|
||||
sudo apt install -y vainfo intel-media-va-driver-non-free i965-va-driver-shaders ffmpeg nginx v4l-utils python3-pip php-fpm mpv libnginx-mod-rtmp alsa-utils vlan git zlib1g-dev
|
||||
sudo pip3 install psutil
|
||||
|
||||
dpkg -i srt-1.5.5-Linux.deb
|
||||
|
||||
cat >/etc/sudoers.d/www-data<<EOL
|
||||
www-data ALL=(ALL) NOPASSWD: ALL
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/main-encoder.service<<EOL
|
||||
[Unit]
|
||||
Description=Main Encoder by ShreeBhattJi
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash /var/www/html/main-encoder.sh
|
||||
WorkingDirectory=/var/www/html
|
||||
Restart=always
|
||||
User=root
|
||||
Environment=PATH=/usr/bin:/usr/local/bin
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
# graph monitor setup
|
||||
cat > /etc/systemd/system/system-monitor.service<<EOL
|
||||
[Unit]
|
||||
Description=Lightweight System Monitor Sampler by ShreeBhattJi
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/python3 /usr/local/bin/nginx_system_monitor_sampler.py
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
User=root
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /usr/local/bin/nginx_system_monitor_sampler.py<<EOL
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Lightweight sampler for nginx static frontend.
|
||||
"""
|
||||
|
||||
import time, json, os
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
import psutil
|
||||
|
||||
OUT_FILE = "/var/www/html/metrics.json"
|
||||
TMP_FILE = OUT_FILE + ".tmp"
|
||||
SAMPLE_INTERVAL = 10.0 # seconds between samples
|
||||
HISTORY_SECONDS = 15 * 60 # 15 minutes
|
||||
MAX_SAMPLES = int(HISTORY_SECONDS / SAMPLE_INTERVAL)
|
||||
|
||||
# circular buffers
|
||||
timestamps = deque(maxlen=MAX_SAMPLES)
|
||||
cpu_hist = deque(maxlen=MAX_SAMPLES)
|
||||
ram_hist = deque(maxlen=MAX_SAMPLES)
|
||||
net_in_hist = deque(maxlen=MAX_SAMPLES)
|
||||
net_out_hist = deque(maxlen=MAX_SAMPLES)
|
||||
disk_read_hist = deque(maxlen=MAX_SAMPLES)
|
||||
disk_write_hist = deque(maxlen=MAX_SAMPLES)
|
||||
disk_percent_hist = deque(maxlen=MAX_SAMPLES)
|
||||
|
||||
_prev_net = psutil.net_io_counters()
|
||||
_prev_disk = psutil.disk_io_counters()
|
||||
_prev_time = time.time()
|
||||
|
||||
def sample_once():
|
||||
global _prev_net, _prev_disk, _prev_time
|
||||
now = time.time()
|
||||
iso = datetime.fromtimestamp(now).isoformat(timespec='seconds')
|
||||
cpu = psutil.cpu_percent(interval=None)
|
||||
ram = psutil.virtual_memory().percent
|
||||
|
||||
net = psutil.net_io_counters()
|
||||
disk = psutil.disk_io_counters()
|
||||
try:
|
||||
disk_percent = psutil.disk_usage("/").percent
|
||||
except Exception:
|
||||
disk_percent = 0.0
|
||||
|
||||
elapsed = now - _prev_time if _prev_time else SAMPLE_INTERVAL
|
||||
if elapsed <= 0:
|
||||
elapsed = SAMPLE_INTERVAL
|
||||
|
||||
in_rate = (net.bytes_recv - _prev_net.bytes_recv) / elapsed
|
||||
out_rate = (net.bytes_sent - _prev_net.bytes_sent) / elapsed
|
||||
|
||||
read_rate = (disk.read_bytes - _prev_disk.read_bytes) / elapsed
|
||||
write_rate = (disk.write_bytes - _prev_disk.write_bytes) / elapsed
|
||||
|
||||
timestamps.append(iso)
|
||||
cpu_hist.append(round(cpu, 2))
|
||||
ram_hist.append(round(ram, 2))
|
||||
net_in_hist.append(int(in_rate))
|
||||
net_out_hist.append(int(out_rate))
|
||||
disk_read_hist.append(int(read_rate))
|
||||
disk_write_hist.append(int(write_rate))
|
||||
disk_percent_hist.append(round(disk_percent, 2))
|
||||
|
||||
_prev_net = net
|
||||
_prev_disk = disk
|
||||
_prev_time = now
|
||||
|
||||
def write_json_atomic():
|
||||
payload = {
|
||||
"timestamps": list(timestamps),
|
||||
"cpu_percent": list(cpu_hist),
|
||||
"ram_percent": list(ram_hist),
|
||||
"net_in_Bps": list(net_in_hist),
|
||||
"net_out_Bps": list(net_out_hist),
|
||||
"disk_read_Bps": list(disk_read_hist),
|
||||
"disk_write_Bps": list(disk_write_hist),
|
||||
"disk_percent": list(disk_percent_hist),
|
||||
"sample_interval": SAMPLE_INTERVAL,
|
||||
"generated_at": datetime.utcnow().isoformat(timespec='seconds') + "Z"
|
||||
}
|
||||
with open(TMP_FILE, "w") as f:
|
||||
json.dump(payload, f)
|
||||
os.replace(TMP_FILE, OUT_FILE)
|
||||
|
||||
def main():
|
||||
global _prev_net, _prev_disk, _prev_time
|
||||
_prev_net = psutil.net_io_counters()
|
||||
_prev_disk = psutil.disk_io_counters()
|
||||
_prev_time = time.time()
|
||||
time.sleep(0.2) # warm-up
|
||||
|
||||
while True:
|
||||
try:
|
||||
sample_once()
|
||||
write_json_atomic()
|
||||
except Exception as e:
|
||||
# systemd journal will capture prints
|
||||
print("Sampler error:", e)
|
||||
time.sleep(SAMPLE_INTERVAL)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
EOL
|
||||
|
||||
# srt server setup
|
||||
sudo chmod +x /etc/srt/srt.sh
|
||||
sudo cp srt /etc/srt/
|
||||
cat > /etc/systemd/system/srt.service<<EOL
|
||||
[Unit]
|
||||
Description=Srt by ShreeBhattJi
|
||||
Documentation=https://dbhatt.org
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
TimeoutStartSec=0
|
||||
Restart=always
|
||||
RestartSec=30s
|
||||
Requires=srt
|
||||
ExecStart=/bin/bash /etc/srt/srt.sh
|
||||
SyslogIdentifier=srt
|
||||
#ExecStop=
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/srt/srt.sh<<EOL
|
||||
/etc/srt/srt -c /var/www/html/sls.conf
|
||||
EOL
|
||||
|
||||
sudo chmod +x /usr/local/bin/nginx_system_monitor_sampler.py
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now system-monitor.service
|
||||
sudo systemctl status system-monitor.service --no-pager
|
||||
sudo systemctl enable --now main-encoder.service
|
||||
sudo systemctl status main-encoder.service --no-pager
|
||||
sudo systemctl enable --now srt.service
|
||||
sudo systemctl status srt.service --no-pager
|
||||
sudo systemctl enable --now nginx.service
|
||||
sudo systemctl status nginx.service --no-pager
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
srt {
|
||||
worker_threads 8;
|
||||
worker_connections 100;
|
||||
|
||||
log_file /var/log/srt/error.log ;
|
||||
log_level info;
|
||||
|
||||
record_hls_path_prefix /tmp/mov/sls;
|
||||
|
||||
server {
|
||||
listen 1937;
|
||||
latency 2000;
|
||||
|
||||
domain_player domain_playerdomain_playerdomain_player;
|
||||
domain_publisher domain_publisherdomain_publisherdomain_publisher;
|
||||
backlog 100;
|
||||
idle_streams_timeout 15;
|
||||
|
||||
app {
|
||||
app_player app_playerapp_playerapp_player ;
|
||||
app_publisher app_publisherapp_publisherapp_publisher ;
|
||||
|
||||
record_hls off;
|
||||
record_hls_segment_duration 10;
|
||||
|
||||
#relay {
|
||||
# type pull;
|
||||
# mode loop;#loop; hash;
|
||||
# reconnect_interval 10;
|
||||
# idle_streams_timeout -1;#s -1: unlimited
|
||||
# upstreams 127.0.0.1:9090?streamid=live.sls.com/live 192.168.1.100:8080/?streamid=live.test.com/live;
|
||||
#}
|
||||
#relay {
|
||||
# type push;
|
||||
# mode all; #all; hash
|
||||
# reconnect_interval 10;
|
||||
# idle_streams_timeout 10;#s -1: unlimited
|
||||
# upstreams 192.168.31.106:8080?streamid=uplive.sls.com/live ;
|
||||
#}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Loading…
Reference in New Issue