1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-03 17:59:55 +02:00
Oinktube/admin/ffmpegMonitor.php
Daniel Neto eb42092b20 Update
2024-12-27 23:50:41 -03:00

320 lines
No EOL
11 KiB
PHP

<?php
global $global, $config;
if (!isset($global['systemRootPath'])) {
require_once '../videos/configuration.php';
}
if (!User::isAdmin()) {
forbiddenPage('You cannot do this');
}
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$csrfToken = $_SESSION['csrf_token'];
// Function to fetch FFMPEG processes
function getFfmpegProcesses()
{
$output = [];
exec("/bin/ps aux | grep ffmpeg | grep -v grep", $output);
//_error_log(print_r($output, true)); // Log the output for debugging
$processes = [];
foreach ($output as $line) {
$parts = preg_split('/\\s+/', $line, 11);
if (count($parts) >= 11) {
$processes[] = [
'user' => $parts[0],
'pid' => $parts[1],
'pidEncrypted' => encryptString($parts[1]),
'cpu' => $parts[2],
'mem' => $parts[3],
'runtime' => $parts[9],
'command' => $parts[10],
];
}
}
// Get memory usage
$memOutput = [];
exec("free -m", $memOutput);
preg_match('/^Mem:\s+(\d+)\s+(\d+)\s+/', $memOutput[1], $memMatches);
$totalMem = isset($memMatches[1]) ? $memMatches[1] : 0;
$usedMem = isset($memMatches[2]) ? $memMatches[2] : 0;
$memUsagePercent = $totalMem > 0 ? round(($usedMem / $totalMem) * 100, 2) : 0;
// Get CPU usage
$cpuOutput = [];
exec("top -bn1 | grep 'Cpu(s)'", $cpuOutput);
preg_match('/(\d+\.\d+)\s+id/', $cpuOutput[0], $cpuMatches);
$cpuIdle = isset($cpuMatches[1]) ? $cpuMatches[1] : 100;
$cpuUsagePercent = 100 - $cpuIdle;
return [
'totalCPU' => $cpuUsagePercent,
'totalMem' => $memUsagePercent,
'processes' => $processes
];
}
// Handle AJAX requests
if (isset($_GET['action']) && $_GET['action'] === 'fetch') {
header('Content-Type: application/json');
echo json_encode(getFfmpegProcesses());
exit;
}
// Handle kill process request securely
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['pid'], $_POST['csrf_token'])) {
if (hash_equals($csrfToken, $_POST['csrf_token'])) {
$pidDecrypted = decryptString($_POST['pid']);
$pid = intval($pidDecrypted);
if ($pid > 0) {
$command = "kill -9 $pid";
$output = [];
$return_var = 0;
// Execute the command and capture the output and return status
exec($command . " 2>&1", $output, $return_var);
// Prepare the response JSON with detailed information
echo json_encode([
'error' => $return_var !== 0,
'msg' => $return_var === 0 ? 'Process killed successfully.' : 'Failed to kill the process.',
'command' => $command,
'output' => $output
]);
exit;
}
}
echo json_encode(['error' => true, 'msg' => 'Invalid request.']);
exit;
}
?>
<script src="<?php echo getURL('node_modules/chart.js/dist/chart.umd.js'); ?>" type="text/javascript"></script>
<script src="<?php echo getURL('view/css/DataTables/datatables.min.js'); ?>" type="text/javascript"></script>
<link href="<?php echo getURL('view/css/DataTables/datatables.min.css'); ?>" rel="stylesheet" type="text/css" />
<div class="container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="text-center">FFmpeg Monitor</h1>
</div>
<div class="panel-body">
<!-- Doughnut Charts for Overall Usage -->
<div class="row">
<div class="col-md-2">
<h4>CPU Usage</h4>
<canvas id="cpuDoughnut" style="width: 100%; height: 250px;"></canvas>
</div>
<div class="col-md-2">
<h4>RAM Usage</h4>
<canvas id="ramDoughnut" style="width: 100%; height: 250px;"></canvas>
</div>
<div class="col-md-8">
<h4>Historical Resource Usage</h4>
<canvas id="historicalLine" style="width: 100%; height: 300px;"></canvas>
</div>
</div>
</div>
<div class="panel-footer">
<!-- Process Table -->
<table id="processTable" class="table table-bordered table-striped">
<thead>
<tr>
<th>User</th>
<th>PID</th>
<th>CPU%</th>
<th>MEM%</th>
<th>Runtime</th> <!-- New Column -->
<th>Command</th>
<th>Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<script>
var updateDuration = 1000;
var updateMaxHistory = 60;
$(document).ready(function() {
const csrfToken = '<?= $csrfToken; ?>';
const historicalCPU = [];
const historicalRAM = [];
const processNames = [];
const processCPU = [];
const processRAM = [];
// Initialize DataTable
const table = $('#processTable').DataTable({
"columns": [{
"width": "20px"
}, // User column
{
"width": "15px"
}, // PID column
{
"width": "15px"
}, // CPU% column
{
"width": "15px"
}, // MEM% column
{
"width": "15px"
}, // Runtime column
null, // Command column
{
"width": "20px",
"orderable": false
} // Action column
]
});
// Initialize Charts
const cpuChart = new Chart(document.getElementById('cpuDoughnut').getContext('2d'), {
type: 'doughnut',
data: {
labels: ['Used CPU', 'Available CPU'],
datasets: [{
data: [0, 100],
backgroundColor: ['#FF6384', '#36A2EB']
}]
},
options: {
responsive: true,
animation: {
duration: updateDuration,
easing: 'easeInOutQuart' // Easing effect for the animation
}
}
});
const ramChart = new Chart(document.getElementById('ramDoughnut').getContext('2d'), {
type: 'doughnut',
data: {
labels: ['Used RAM', 'Available RAM'],
datasets: [{
data: [0, 100],
backgroundColor: ['#FF9F40', '#4BC0C0']
}]
},
options: {
responsive: true,
animation: {
duration: updateDuration, // 2-second animation
easing: 'easeInOutQuart' // Easing effect for the animation
}
}
});
const historicalLine = new Chart(document.getElementById('historicalLine').getContext('2d'), {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'CPU%',
data: [],
borderColor: '#FF6384'
}, {
label: 'RAM%',
data: [],
borderColor: '#4BC0C0'
}]
},
options: {
responsive: true,
animation: {
duration: updateDuration, // 2-second animation
easing: 'easeInOutQuart' // Easing effect for the animation
}
}
});
// Fetch processes and update the table and charts
function fetchCPUProcesses() {
$.ajax({
url: webSiteRootURL + 'admin/ffmpegMonitor.php?action=fetch',
type: 'GET',
dataType: 'json',
success: function(data) {
table.clear();
// If there are processes, add them to the table
if (data.processes.length > 0) {
data.processes.forEach(process => {
table.row.add([
process.user,
process.pid,
process.cpu,
process.mem,
process.runtime,
process.command,
`<button class="btn btn-danger btn-kill btn-block" data-pid="${process.pidEncrypted}">Kill</button>`
]);
});
} else {
// Add a placeholder row if no processes exist
table.row.add(['-', '-', '-', '-', '-', 'No FFmpeg processes running', '-']);
}
table.draw();
// Update Doughnut Charts
const avgCPU = data.totalCPU || 0;
const avgRAM = data.totalMem || 0;
cpuChart.data.datasets[0].data = [avgCPU, 100 - avgCPU];
ramChart.data.datasets[0].data = [avgRAM, 100 - avgRAM];
cpuChart.update();
ramChart.update();
// Update Historical Line Chart
const now = new Date().toLocaleTimeString();
// Push new data
historicalCPU.push(avgCPU);
historicalRAM.push(avgRAM);
historicalLine.data.labels.push(now);
// Maintain a maximum of 10 elements
if (historicalCPU.length > updateMaxHistory) {
historicalCPU.shift(); // Remove the oldest CPU data
}
if (historicalRAM.length > updateMaxHistory) {
historicalRAM.shift(); // Remove the oldest RAM data
}
if (historicalLine.data.labels.length > updateMaxHistory) {
historicalLine.data.labels.shift(); // Remove the oldest label
}
// Update the chart
historicalLine.data.datasets[0].data = historicalCPU;
historicalLine.data.datasets[1].data = historicalRAM;
historicalLine.update();
setTimeout(() => {
fetchCPUProcesses();
}, updateDuration);
},
error: function() {
alert('Failed to fetch process data.');
}
});
}
// Initial fetch
fetchCPUProcesses();
});
</script>