trackwhat-small / src /js /lib /captureFlow.js
eggman-poff's picture
Upload folder using huggingface_hub
9435b27 verified
Raw
History Blame Contribute Delete
10.2 kB
// @ts-nocheck
import { captureModeSuffix, isSyntheticLoopMode } from "./config.js";
import { captureFrame, drawSyntheticFrame } from "./captureCanvas.js";
import { setButtonState, setCaptureStatus, setLoopButtonState } from "./captureUi.js";
import { clearScheduledScan, scheduleNextScan, startCountdownTimer, stopCountdownTimer, updateCountdown } from "./timing.js";
import { state } from "./state.js";
export function createCaptureFlow({ requestAnalysis, recoverStaleAnalysis, setAnalysisPending }) {
async function captureOnceAndAnalyze() {
if (isSyntheticLoopMode()) {
drawSyntheticFrame();
setCaptureStatus(`Analyzing current desktop capture${captureModeSuffix()}...`);
state.allowAnalysisClick = true;
requestAnalysis(false);
state.allowAnalysisClick = false;
return;
}
const source = (document.querySelector('#desktop-capture-source select, #desktop-capture-source input')?.value || state.source || '🖥 Screen').toLowerCase();
if (!navigator.mediaDevices?.getDisplayMedia) {
setCaptureStatus('Desktop capture is not available in this browser or iframe.');
return;
}
let stream = null;
let video = null;
try {
setCaptureStatus('Waiting for browser screen picker...');
stream = await navigator.mediaDevices.getDisplayMedia({
video: { cursor: 'always', displaySurface: source.includes('window') ? 'window' : 'monitor' },
monitorTypeSurfaces: 'include',
selfBrowserSurface: 'exclude',
surfaceSwitching: 'include',
audio: false,
});
video = document.createElement('video');
video.autoplay = true;
video.muted = true;
video.playsInline = true;
video.srcObject = stream;
await video.play();
state.video = video;
state.stream = stream;
state.sessionStartedAt = Date.now();
state.active = true;
state.loopPaused = false;
state.sessionPausedMs = 0;
state.sessionPauseStartedAt = null;
captureFrame();
state.allowAnalysisClick = true;
setCaptureStatus('Analyzing selected desktop frame...');
requestAnalysis(false);
state.allowAnalysisClick = false;
} catch (error) {
if (stream) for (const track of stream.getTracks()) track.stop();
state.video = null;
state.stream = null;
state.active = false;
state.sessionStartedAt = null;
state.loopPaused = false;
state.sessionPausedMs = 0;
state.sessionPauseStartedAt = null;
if (state.previewTimer) {
window.clearInterval(state.previewTimer);
state.previewTimer = null;
}
setButtonState(false);
const message = error?.name === 'NotAllowedError'
? 'Desktop capture was cancelled or blocked. Pick a screen/window to analyze one frame.'
: `Desktop capture failed: ${error?.message || error}`;
setCaptureStatus(message);
console.warn('One-shot desktop capture failed:', error);
} finally {
if (video) video.srcObject = null;
if (stream) for (const track of stream.getTracks()) track.stop();
if (state.previewTimer) {
window.clearInterval(state.previewTimer);
state.previewTimer = null;
}
state.video = null;
state.stream = null;
state.active = false;
state.sessionStartedAt = null;
state.loopPaused = false;
state.sessionPausedMs = 0;
state.sessionPauseStartedAt = null;
setButtonState(false);
}
}
function captureAndAnalyze(resetTimer = false, rearmNextScan = true) {
window['__trackwhatDesktopCaptureTrace']?.('analysis.capture', {
resetTimer, active: state.active, analysisPending: state.analysisPending, scanTimer: Boolean(state.scanTimer),
});
if (resetTimer && state.scanTimer) {
window.clearTimeout(state.scanTimer);
state.scanTimer = null;
}
state.nextScanAt = null;
if (captureFrame()) window.setTimeout(() => requestAnalysis(rearmNextScan), 250);
else if (state.active) recoverStaleAnalysis('frame-not-ready');
}
state.captureAndAnalyze = captureAndAnalyze;
function startLivePreviewLoop() {
if (state.previewTimer) window.clearInterval(state.previewTimer);
state.previewTimer = window.setInterval(() => { if (state.active) captureFrame(false); }, 1000);
}
async function startCapture() {
if (state.active) return;
window['__trackwhatDesktopCaptureTrace']?.('capture.start', { active: state.active, automationMode: state.automationMode });
const source = (document.querySelector('#desktop-capture-source select, #desktop-capture-source input')?.value || state.source || '🖥 Screen').toLowerCase();
let stream = null;
let video = null;
try {
if (isSyntheticLoopMode()) {
state.sessionStartedAt = Date.now();
state.loopPaused = false;
state.sessionPausedMs = 0;
state.sessionPauseStartedAt = null;
setButtonState(true);
state.active = true;
captureAndAnalyze();
startCountdownTimer();
return;
}
if (!navigator.mediaDevices?.getDisplayMedia) throw new Error('Screen capture is not available in this browser or iframe.');
setCaptureStatus('Waiting for browser screen picker...');
stream = await navigator.mediaDevices.getDisplayMedia({
video: { cursor: 'always', displaySurface: source.includes('window') ? 'window' : 'monitor' },
monitorTypeSurfaces: 'include',
selfBrowserSurface: 'exclude',
surfaceSwitching: 'include',
audio: false,
});
state.stream = stream;
video = document.createElement('video');
state.video = video;
video.autoplay = true;
video.muted = true;
video.playsInline = true;
video.srcObject = stream;
await video.play();
state.active = true;
state.sessionStartedAt = Date.now();
state.loopPaused = false;
setButtonState(true);
captureAndAnalyze();
startLivePreviewLoop();
startCountdownTimer();
const track = stream.getVideoTracks()[0];
if (track) track.addEventListener('ended', stopCapture);
return;
} catch (error) {
setButtonState(false);
const message = error?.name === 'NotAllowedError'
? 'Desktop capture was cancelled or blocked. Click Start desktop capture and choose a screen/window in the browser picker.'
: `Desktop capture failed: ${error?.message || error}`;
setCaptureStatus(message);
console.warn('Desktop capture start failed:', error);
if (stream) for (const track of stream.getTracks()) track.stop();
state.video = null;
state.stream = null;
state.active = false;
state.sessionStartedAt = null;
state.loopPaused = false;
if (state.previewTimer) {
window.clearInterval(state.previewTimer);
state.previewTimer = null;
}
}
}
function stopCapture() {
window['__trackwhatDesktopCaptureTrace']?.('capture.stop', { active: state.active, analysisPending: state.analysisPending, scanTimer: Boolean(state.scanTimer), previewTimer: Boolean(state.previewTimer) });
if (state.timer) { window.clearInterval(state.timer); state.timer = null; }
if (state.analysisGuardTimer) { window.clearTimeout(state.analysisGuardTimer); state.analysisGuardTimer = null; }
if (state.scanTimer) { window.clearTimeout(state.scanTimer); state.scanTimer = null; }
if (state.previewTimer) { window.clearInterval(state.previewTimer); state.previewTimer = null; }
stopCountdownTimer();
if (state.analysisStartTimer) { window.clearTimeout(state.analysisStartTimer); state.analysisStartTimer = null; }
setAnalysisPending(false);
state.allowAnalysisClick = false;
state.nextScanAt = null;
state.loopPaused = false;
state.sessionPausedMs = 0;
state.sessionPauseStartedAt = null;
if (state.stream) {
for (const track of state.stream.getTracks()) track.stop();
state.stream = null;
}
state.active = false;
state.sessionStartedAt = null;
state.lastProjectName = '';
state.sameProjectStreak = 0;
state.smartDelayMs = 0;
setButtonState(false);
}
function pauseCaptureLoop() {
if (!state.active || state.loopPaused) return;
window['__trackwhatDesktopCaptureTrace']?.('capture.pause', {
active: state.active,
analysisPending: state.analysisPending,
scanTimer: Boolean(state.scanTimer),
previewTimer: Boolean(state.previewTimer),
});
state.loopPaused = true;
state.sessionPauseStartedAt = Date.now();
if (state.scanTimer) {
window.clearTimeout(state.scanTimer);
state.scanTimer = null;
}
if (state.previewTimer) {
window.clearInterval(state.previewTimer);
state.previewTimer = null;
}
clearScheduledScan();
setButtonState(true);
setLoopButtonState(true, true);
updateCountdown();
setCaptureStatus(`Desktop capture paused${captureModeSuffix()}. Click Resume loop to continue.`);
}
function resumeCaptureLoop() {
if (!state.active || !state.loopPaused) return;
window['__trackwhatDesktopCaptureTrace']?.('capture.resume', {
active: state.active,
analysisPending: state.analysisPending,
});
if (state.sessionPauseStartedAt) {
state.sessionPausedMs = (state.sessionPausedMs || 0) + Math.max(0, Date.now() - state.sessionPauseStartedAt);
}
state.sessionPauseStartedAt = null;
state.loopPaused = false;
startLivePreviewLoop();
setButtonState(true);
setLoopButtonState(false, true);
startCountdownTimer();
if (!state.analysisPending) {
scheduleNextScan();
} else {
updateCountdown();
}
}
async function toggleCapture() {
if (state.active) stopCapture();
else await startCapture();
}
function toggleCaptureLoop() {
if (!state.active) return;
if (state.loopPaused) resumeCaptureLoop();
else pauseCaptureLoop();
}
return { captureOnceAndAnalyze, captureAndAnalyze, startLivePreviewLoop, startCapture, stopCapture, toggleCapture, pauseCaptureLoop, resumeCaptureLoop, toggleCaptureLoop };
}