Fixed a bug where a resumed recording wouldn't update the image Part 2
Template tests / tests (push) Successful in 1m51s

This commit is contained in:
Iisyourdad
2026-06-11 11:57:55 -05:00
parent 72b3f10a8a
commit c352741809
3 changed files with 41 additions and 7 deletions
+8 -3
View File
@@ -24,6 +24,7 @@ const { encodePng } = require('../core/png');
const CLICK_DEBOUNCE_MS = 700; const CLICK_DEBOUNCE_MS = 700;
const CLICK_CAPTURE_CACHE_MS = 75; const CLICK_CAPTURE_CACHE_MS = 75;
const CLICK_CAPTURE_CACHE_MAX_AGE_MS = 400;
const CLICK_CAPTURE_HIDE_DELAY_MS = 25; const CLICK_CAPTURE_HIDE_DELAY_MS = 25;
function hasBinary(name) { function hasBinary(name) {
@@ -257,9 +258,13 @@ class CaptureService {
try { try {
const mode = this.settings.get('capture.mode') || 'fullscreen'; const mode = this.settings.get('capture.mode') || 'fullscreen';
const grabMode = mode === 'region' ? 'fullscreen' : mode; const grabMode = mode === 'region' ? 'fullscreen' : mode;
const cached = trigger === 'click' && this.captureCache && this.captureCache.mode === grabMode // The background refresh loop (startClickCaptureCache) keeps this
? this.captureCache // updated every ~75ms; if it's gone stale (refresh errors silently and
: null; // stops updating, or the cache was never refreshed after a resume),
// fall back to a fresh shot rather than reusing an old background.
const cacheFresh = this.captureCache && this.captureCache.mode === grabMode
&& Date.now() - this.captureCache.capturedAt <= CLICK_CAPTURE_CACHE_MAX_AGE_MS;
const cached = trigger === 'click' && cacheFresh ? this.captureCache : null;
const finalResult = cached const finalResult = cached
? this.storeFrameAsStep(this.session.guideId, grabMode, cached, clickPos) ? this.storeFrameAsStep(this.session.guideId, grabMode, cached, clickPos)
: await this.shoot({ : await this.shoot({
+6 -4
View File
@@ -92,10 +92,12 @@ Initial release.
literal text "undefined" by an old bug); a corrupted file is now literal text "undefined" by an old bug); a corrupted file is now
treated as empty instead of crashing the dialog, and is overwritten treated as empty instead of crashing the dialog, and is overwritten
with valid JSON the next time settings are saved. with valid JSON the next time settings are saved.
- Resuming a paused capture session no longer reuses the same stale - Click captures no longer reuse the same stale background screenshot
background screenshot for every click capture (only the click marker for every step (only the click marker moved). Pausing now fully resets
moved); pausing now fully resets the click-capture cache so resuming the click-capture cache so resuming starts a fresh background refresh
starts a fresh background refresh loop. loop, and a cached frame older than 400ms (e.g. if the background
refresh silently stops working) is now discarded in favor of a fresh
screenshot.
### Added (initial feature set) ### Added (initial feature set)
+27
View File
@@ -143,6 +143,33 @@ test('click-triggered capture marks the click-time cursor position, not the cach
assert.ok(Math.abs(marker.y - (0.5 - (d * 120 / 80) / 2)) < 1e-9); assert.ok(Math.abs(marker.y - (0.5 - (d * 120 / 80) / 2)) < 1e-9);
}); });
test('click-triggered session capture falls back to a fresh shot when the cached frame is stale', async () => {
const service = makeService();
service.session = { guideId: 'guide-stale', paused: false, count: 0, intervalSec: 0 };
// A frame that's well past the cache's max age — e.g. the background
// refresh loop died (errored silently, or never restarted after a
// pause/resume) and left a frozen, increasingly-stale frame behind.
service.captureCache = {
mode: 'fullscreen',
png: Buffer.from('stale-png'),
size: { width: 120, height: 80 },
display: { bounds: { x: 0, y: 0, width: 120, height: 80 } },
cursor: { x: 60, y: 40 },
capturedAt: Date.now() - 10_000,
};
let shootCalled = false;
service.shoot = async () => {
shootCalled = true;
return { ok: true, step: { stepId: 'fresh-step' } };
};
const result = await service.sessionCapture('click', { x: 1, y: 1 });
assert.equal(result.ok, true);
assert.equal(shootCalled, true, 'a stale cached frame must not be reused');
});
test('live-shot click capture also marks the click-time cursor position', async () => { test('live-shot click capture also marks the click-time cursor position', async () => {
const service = makeService(); const service = makeService();
service.settings.get = (key) => { service.settings.get = (key) => {