feat: support configurable random delays between auto steps

- 合并 PR #44 的核心改动:新增 Auto 步间随机延迟配置,并在后台执行前应用该随机等待\n- 本地补充修复:无\n- 影响范围:background auto orchestration、sidepanel auto settings、README、tests
This commit is contained in:
QLHazyCoder
2026-04-13 16:51:52 +08:00
5 changed files with 265 additions and 0 deletions
+13
View File
@@ -192,6 +192,19 @@
</div>
</div>
</div>
<div class="data-row">
<span class="data-label">步间随机</span>
<div class="data-inline auto-delay-inline">
<div class="auto-delay-controls">
<input type="number" id="input-auto-step-delay-min-seconds" class="data-input auto-delay-input" value="12" min="0"
max="600" step="1" title="自动运行每一步执行前的最小随机等待秒数" />
<span class="data-unit">~</span>
<input type="number" id="input-auto-step-delay-max-seconds" class="data-input auto-delay-input" value="18" min="0"
max="600" step="1" title="自动运行每一步执行前的最大随机等待秒数" />
<span class="data-unit"></span>
</div>
</div>
</div>
<div class="data-row">
<span class="data-label">OAuth</span>
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
+70
View File
@@ -85,6 +85,8 @@ const inputRunCount = document.getElementById('input-run-count');
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
const inputAutoStepDelayMinSeconds = document.getElementById('input-auto-step-delay-min-seconds');
const inputAutoStepDelayMaxSeconds = document.getElementById('input-auto-step-delay-max-seconds');
const autoStartModal = document.getElementById('auto-start-modal');
const autoStartTitle = autoStartModal?.querySelector('.modal-title');
const autoStartMessage = document.getElementById('auto-start-message');
@@ -108,6 +110,10 @@ const SKIPPABLE_STEPS = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9]);
const AUTO_DELAY_MIN_MINUTES = 1;
const AUTO_DELAY_MAX_MINUTES = 1440;
const AUTO_DELAY_DEFAULT_MINUTES = 30;
const AUTO_STEP_DELAY_MIN_SECONDS = 0;
const AUTO_STEP_DELAY_MAX_SECONDS = 600;
const AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS = 12;
const AUTO_STEP_DELAY_DEFAULT_MAX_SECONDS = 18;
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
let latestState = null;
@@ -447,6 +453,23 @@ function normalizeAutoDelayMinutes(value) {
return Math.min(AUTO_DELAY_MAX_MINUTES, Math.max(AUTO_DELAY_MIN_MINUTES, Math.floor(numeric)));
}
function normalizeAutoStepDelaySeconds(value, fallback = AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS) {
const numeric = Number(value);
if (!Number.isFinite(numeric)) {
return fallback;
}
return Math.min(AUTO_STEP_DELAY_MAX_SECONDS, Math.max(AUTO_STEP_DELAY_MIN_SECONDS, Math.floor(numeric)));
}
function normalizeAutoStepDelayRange(minValue, maxValue) {
const minSeconds = normalizeAutoStepDelaySeconds(minValue, AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS);
const maxSeconds = Math.max(
minSeconds,
normalizeAutoStepDelaySeconds(maxValue, AUTO_STEP_DELAY_DEFAULT_MAX_SECONDS)
);
return { minSeconds, maxSeconds };
}
function updateAutoDelayInputState() {
const scheduled = isAutoRunScheduledPhase();
inputAutoDelayEnabled.disabled = scheduled;
@@ -598,6 +621,10 @@ function collectSettingsPayload() {
const selectedCloudflareDomain = normalizeCloudflareDomainValue(
!cloudflareDomainEditMode ? selectCfDomain.value : activeDomain
) || activeDomain;
const autoStepDelayRange = normalizeAutoStepDelayRange(
inputAutoStepDelayMinSeconds.value,
inputAutoStepDelayMaxSeconds.value
);
return {
panelMode: selectPanelMode.value,
vpsUrl: inputVpsUrl.value.trim(),
@@ -617,6 +644,8 @@ function collectSettingsPayload() {
autoRunSkipFailures: inputAutoSkipFailures.checked,
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
autoStepRandomDelayMinSeconds: autoStepDelayRange.minSeconds,
autoStepRandomDelayMaxSeconds: autoStepDelayRange.maxSeconds,
};
}
@@ -858,6 +887,12 @@ function applySettingsState(state) {
inputAutoSkipFailures.checked = Boolean(state?.autoRunSkipFailures);
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
const autoStepDelayRange = normalizeAutoStepDelayRange(
state?.autoStepRandomDelayMinSeconds,
state?.autoStepRandomDelayMaxSeconds
);
inputAutoStepDelayMinSeconds.value = String(autoStepDelayRange.minSeconds);
inputAutoStepDelayMaxSeconds.value = String(autoStepDelayRange.maxSeconds);
if (state?.autoRunTotalRuns) {
inputRunCount.value = String(state.autoRunTotalRuns);
}
@@ -2380,6 +2415,33 @@ inputAutoDelayMinutes.addEventListener('blur', () => {
saveSettings({ silent: true }).catch(() => { });
});
function syncAutoStepDelayInputs() {
const range = normalizeAutoStepDelayRange(
inputAutoStepDelayMinSeconds.value,
inputAutoStepDelayMaxSeconds.value
);
inputAutoStepDelayMinSeconds.value = String(range.minSeconds);
inputAutoStepDelayMaxSeconds.value = String(range.maxSeconds);
}
inputAutoStepDelayMinSeconds.addEventListener('input', () => {
markSettingsDirty(true);
scheduleSettingsAutoSave();
});
inputAutoStepDelayMinSeconds.addEventListener('blur', () => {
syncAutoStepDelayInputs();
saveSettings({ silent: true }).catch(() => { });
});
inputAutoStepDelayMaxSeconds.addEventListener('input', () => {
markSettingsDirty(true);
scheduleSettingsAutoSave();
});
inputAutoStepDelayMaxSeconds.addEventListener('blur', () => {
syncAutoStepDelayInputs();
saveSettings({ silent: true }).catch(() => { });
});
// ============================================================
// Listen for Background broadcasts
// ============================================================
@@ -2477,6 +2539,14 @@ chrome.runtime.onMessage.addListener((message) => {
if (message.payload.autoRunDelayMinutes !== undefined) {
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(message.payload.autoRunDelayMinutes));
}
if (message.payload.autoStepRandomDelayMinSeconds !== undefined || message.payload.autoStepRandomDelayMaxSeconds !== undefined) {
const autoStepDelayRange = normalizeAutoStepDelayRange(
message.payload.autoStepRandomDelayMinSeconds ?? inputAutoStepDelayMinSeconds.value,
message.payload.autoStepRandomDelayMaxSeconds ?? inputAutoStepDelayMaxSeconds.value
);
inputAutoStepDelayMinSeconds.value = String(autoStepDelayRange.minSeconds);
inputAutoStepDelayMaxSeconds.value = String(autoStepDelayRange.maxSeconds);
}
break;
}