fix : opening link 2
All checks were successful
release / build (push) Successful in 26s
release / verify-windows (push) Successful in 1m4s

This commit is contained in:
jeanotx32
2026-08-12 01:16:52 +02:00
parent a38baf9a88
commit 3bd4d5f2ba
4 changed files with 95 additions and 5 deletions

View File

@@ -62,7 +62,10 @@ type ObsSnapshot = Pick<
| 'cpuUsage'
| 'fps'
| 'droppedFrames'
| 'outputTotalFrames'
| 'renderSkippedFrames'
| 'renderTotalFrames'
| 'frameRenderTimeMs'
>;
const RECONNECT_DELAY_MS = 5000;
@@ -512,7 +515,10 @@ export class ObsController extends EventEmitter {
cpuUsage: stats.cpuUsage,
fps: stats.activeFps,
droppedFrames: stats.outputSkippedFrames,
outputTotalFrames: stats.outputTotalFrames,
renderSkippedFrames: stats.renderSkippedFrames,
renderTotalFrames: stats.renderTotalFrames,
frameRenderTimeMs: stats.averageFrameRenderTime,
};
} catch (err) {
this.lastError = err instanceof Error ? err.message : String(err);

View File

@@ -532,8 +532,23 @@ export interface AgentStatus {
/** Statistiques OBS. */
cpuUsage?: number;
fps?: number;
/**
* Deux goulots distincts, à ne pas confondre — c'est eux qui désignent la
* cause d'une chute de performance.
*
* `renderSkipped` : la composition de la scène n'a pas tenu la cadence. En
* cause : la méthode de capture, la définition, ou un bureau sans
* accélération 3D. Changer d'encodeur n'y ferait rien.
*
* `droppedFrames` (encodage) : la scène était prête mais l'encodeur n'a pas
* suivi. Là, le preset et l'encodeur sont les bons leviers.
*/
droppedFrames?: number;
outputTotalFrames?: number;
renderSkippedFrames?: number;
renderTotalFrames?: number;
/** Durée moyenne de composition d'une image, en millisecondes. */
frameRenderTimeMs?: number;
/** Statistiques machine (collectées par l'agent, pas par OBS). */
systemCpu?: number;

View File

@@ -102,7 +102,24 @@ export function AgentCard({
<Metric label="Disque libre" value={formatBytes(status.diskFreeBytes)} />
<Metric label="CPU OBS" value={formatPercent(status.cpuUsage)} />
<Metric label="FPS" value={status.fps ? status.fps.toFixed(0) : '—'} />
<Metric label="Frames perdues" value={String(status.droppedFrames ?? '—')} />
<Metric
label="Rendu"
value={
status.frameRenderTimeMs === undefined
? '—'
: `${status.frameRenderTimeMs.toFixed(1)} ms`
}
/>
<Metric
label="Perdu · rendu"
value={formatSkipped(status.renderSkippedFrames, status.renderTotalFrames)}
title="Composition de la scène trop lente : capture, définition, accélération 3D"
/>
<Metric
label="Perdu · encodage"
value={formatSkipped(status.droppedFrames, status.outputTotalFrames)}
title="Encodeur en retard : preset trop lourd ou CPU saturé"
/>
</div>
<div className="row">
@@ -260,15 +277,39 @@ function WatchStrip({
);
}
function Metric({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
function Metric({
label,
value,
mono,
title,
}: {
label: string;
value: string;
mono?: boolean;
title?: string;
}) {
return (
<div className="metric">
<div className="metric" title={title}>
<span className="metric-label">{label}</span>
<span className={`metric-value${mono ? ' mono' : ''}`}>{value}</span>
</div>
);
}
/**
* Images perdues, en valeur absolue et en part du total.
*
* Les compteurs d'OBS cumulent depuis son lancement : « 4 200 » ne dit rien
* seul, « 4 200 (0,3 %) » dit que tout va bien, « 4 200 (38 %) » qu'il faut
* agir.
*/
function formatSkipped(skipped?: number, total?: number): string {
if (skipped === undefined) return '—';
if (!total) return String(skipped);
const share = (skipped / total) * 100;
return `${skipped} (${share < 0.1 && skipped > 0 ? '<0,1' : share.toFixed(1).replace('.', ',')} %)`;
}
function basename(filePath: string): string {
const parts = filePath.split(/[\\/]/);
return parts[parts.length - 1] ?? filePath;