Plugin lives in Plugin/ — invisible to User Script Plugin. dev_install.sh symlinks into /usr/local/emhttp/plugins/varaverk/ for development. Pages: Monitor (5s poll), Scheduler (orchs + Advanced children, toggle + cron), Config (raw editor, host-aware file access), Docs (markdown + live $VAR substitution). API endpoints: monitor.php (JSON), scheduler.php (writes schedule.json + cron.d), config.php (writes conf files with host permission check). Includes: config.php (parser, host detection, var map), scheduler.php (job tree, cron.d rebuild), monitor.php (docker, GPU, resources, fallback, transcode), docs.php (file tree, var substitution, Parsedown renderer).
86 lines
2.7 KiB
PHP
86 lines
2.7 KiB
PHP
<?php require_once dirname(__DIR__) . '/include/monitor.php'; ?>
|
|
|
|
<div id="vv-monitor">
|
|
|
|
<div class="vv-row">
|
|
<div class="vv-card" id="vv-fallback">
|
|
<h3>Fallback State</h3>
|
|
<div class="vv-state-badge" id="vv-fallback-state">—</div>
|
|
</div>
|
|
|
|
<div class="vv-card" id="vv-resources">
|
|
<h3>Resources</h3>
|
|
<div id="vv-resource-body">Loading...</div>
|
|
</div>
|
|
|
|
<div class="vv-card" id="vv-gpu-card">
|
|
<h3>GPU</h3>
|
|
<div id="vv-gpu-body">Loading...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="vv-row">
|
|
<div class="vv-card vv-wide" id="vv-transcode">
|
|
<h3>Transcode</h3>
|
|
<div id="vv-transcode-body">Loading...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="vv-row">
|
|
<div class="vv-card vv-wide" id="vv-docker">
|
|
<h3>Containers</h3>
|
|
<table id="vv-docker-table">
|
|
<thead><tr><th>Name</th><th>Status</th><th>Image</th></tr></thead>
|
|
<tbody id="vv-docker-body"><tr><td colspan="3">Loading...</td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
// Poll monitor API every 5 seconds
|
|
function vvPollMonitor() {
|
|
fetch('/plugins/varaverk/api/monitor.php')
|
|
.then(r => r.json())
|
|
.then(d => {
|
|
// Fallback state
|
|
const fb = d.fallback ?? {};
|
|
const badge = document.getElementById('vv-fallback-state');
|
|
badge.textContent = fb.state ?? '—';
|
|
badge.className = 'vv-state-badge vv-state-' + (fb.state ?? 'unknown').toLowerCase();
|
|
|
|
// Resources
|
|
const res = d.resources ?? {};
|
|
document.getElementById('vv-resource-body').innerHTML =
|
|
`<p>RAM: ${res.ram_free_mb ?? '—'} MB free / ${res.ram_total_mb ?? '—'} MB</p>
|
|
<p>CPU: ${res.cpu_percent ?? '—'}%</p>
|
|
<p>Ramdisk: ${res.ramdisk?.used_mb ?? '—'} MB / ${res.ramdisk?.size_mb ?? '—'} MB</p>`;
|
|
|
|
// GPU
|
|
const gpu = d.gpu ?? {};
|
|
if (gpu.available) {
|
|
document.getElementById('vv-gpu-body').innerHTML =
|
|
`<p>${gpu.name}</p>
|
|
<p>VRAM: ${gpu.memory_used} / ${gpu.memory_total} MB</p>
|
|
<p>Util: ${gpu.utilization}% Temp: ${gpu.temperature}°C</p>`;
|
|
} else {
|
|
document.getElementById('vv-gpu-body').innerHTML = '<p>No GPU detected</p>';
|
|
}
|
|
|
|
// Docker
|
|
const containers = d.containers ?? [];
|
|
const tbody = document.getElementById('vv-docker-body');
|
|
tbody.innerHTML = containers.length
|
|
? containers.map(c =>
|
|
`<tr><td>${c.name}</td><td class="vv-status-${c.status.startsWith('Up') ? 'up' : 'down'}">${c.status}</td><td>${c.image}</td></tr>`
|
|
).join('')
|
|
: '<tr><td colspan="3">No running containers</td></tr>';
|
|
})
|
|
.catch(() => {}); // silent on poll failure
|
|
}
|
|
|
|
vvPollMonitor();
|
|
setInterval(vvPollMonitor, 5000);
|
|
</script>
|