Forráskód Böngészése

Make add-phone cooldown configurable

chendeben 4 hónapja
szülő
commit
fd942b3011

+ 27 - 0
background.js

@@ -150,6 +150,8 @@ const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
 const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
 const AUTO_RUN_DELAY_MIN_MINUTES = 1;
 const AUTO_RUN_DELAY_MAX_MINUTES = 1440;
+const AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES = 1;
+const AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES = 1440;
 const AUTO_RUN_RETRY_DELAY_MS = 3000;
 const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
 const AUTO_STEP_DELAY_MIN_ALLOWED_SECONDS = 0;
@@ -157,6 +159,7 @@ const AUTO_STEP_DELAY_MAX_ALLOWED_SECONDS = 600;
 const VERIFICATION_RESEND_COUNT_MIN = 0;
 const VERIFICATION_RESEND_COUNT_MAX = 20;
 const DEFAULT_VERIFICATION_RESEND_COUNT = 4;
+const DEFAULT_ADD_PHONE_PAUSE_MINUTES = 10;
 const LEGACY_AUTO_STEP_DELAY_KEYS = ['autoStepRandomDelayMinSeconds', 'autoStepRandomDelayMaxSeconds'];
 const LEGACY_VERIFICATION_RESEND_COUNT_KEYS = ['signupVerificationResendCount', 'loginVerificationResendCount'];
 const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
@@ -221,6 +224,7 @@ const PERSISTED_SETTING_DEFAULTS = {
   customPassword: '',
   autoRunSkipFailures: false,
   autoRunFallbackThreadIntervalMinutes: 0,
+  autoRunAddPhonePauseMinutes: DEFAULT_ADD_PHONE_PAUSE_MINUTES,
   autoRunDelayEnabled: false,
   autoRunDelayMinutes: 30,
   autoStepDelaySeconds: null,
@@ -352,6 +356,23 @@ function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
   );
 }
 
+function normalizeAddPhonePauseMinutes(value, fallback = DEFAULT_ADD_PHONE_PAUSE_MINUTES) {
+  const rawValue = String(value ?? '').trim();
+  if (!rawValue) {
+    return fallback;
+  }
+
+  const numeric = Number(rawValue);
+  if (!Number.isFinite(numeric)) {
+    return fallback;
+  }
+
+  return Math.min(
+    AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES,
+    Math.max(AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES, Math.floor(numeric))
+  );
+}
+
 function normalizeAutoStepDelaySeconds(value, fallback = null) {
   const rawValue = String(value ?? '').trim();
   if (!rawValue) {
@@ -842,6 +863,8 @@ function normalizePersistentSettingValue(key, value) {
       return Boolean(value);
     case 'autoRunFallbackThreadIntervalMinutes':
       return normalizeAutoRunFallbackThreadIntervalMinutes(value);
+    case 'autoRunAddPhonePauseMinutes':
+      return normalizeAddPhonePauseMinutes(value, DEFAULT_ADD_PHONE_PAUSE_MINUTES);
     case 'autoRunDelayMinutes':
       return normalizeAutoRunDelayMinutes(value);
     case 'autoStepDelaySeconds':
@@ -5184,6 +5207,10 @@ const autoRunController = self.MultiPageBackgroundAutoRunController?.createAutoR
   broadcastAutoRunStatus,
   broadcastStopToContentScripts,
   cancelPendingCommands,
+  chooseAddPhonePauseMinutes: async () => normalizeAddPhonePauseMinutes(
+    (await getState()).autoRunAddPhonePauseMinutes,
+    DEFAULT_ADD_PHONE_PAUSE_MINUTES
+  ),
   clearStopRequest: () => clearStopRequest(),
   createAutoRunSessionId: () => createAutoRunSessionId(),
   getAutoRunStatusPayload,

+ 7 - 7
background/auto-run-controller.js

@@ -37,16 +37,16 @@
       waitForRunningStepsToFinish,
     } = deps;
 
-    function getAddPhonePauseMinutes() {
+    async function getAddPhonePauseMinutes() {
       const candidate = Number(
         typeof chooseAddPhonePauseMinutes === 'function'
-          ? chooseAddPhonePauseMinutes()
-          : (30 + Math.floor(Math.random() * 31))
+          ? await chooseAddPhonePauseMinutes()
+          : (await getState()).autoRunAddPhonePauseMinutes
       );
-      if (!Number.isFinite(candidate)) {
-        return 30;
+      if (!Number.isFinite(candidate) || candidate <= 0) {
+        return 45;
       }
-      return Math.min(60, Math.max(30, Math.floor(candidate)));
+      return Math.floor(candidate);
     }
 
     function buildFreshAttemptPreservedTabRuntime(prevState = {}) {
@@ -521,7 +521,7 @@
               cancelPendingCommands('当前轮因认证流程进入 add-phone 已终止。');
               await broadcastStopToContentScripts();
               if (targetRun < totalRuns) {
-                const pauseMinutes = getAddPhonePauseMinutes();
+                const pauseMinutes = await getAddPhonePauseMinutes();
                 await addLog(
                   `第 ${targetRun}/${totalRuns} 轮触发 add-phone/手机号页,当前轮记为失败,等待 ${pauseMinutes} 分钟后继续下一轮。`,
                   'warn'

+ 13 - 0
sidepanel/sidepanel.html

@@ -287,6 +287,19 @@
           </div>
         </div>
       </div>
+      <div class="data-row">
+        <span class="data-label">手机号冷却</span>
+        <div class="data-inline auto-delay-inline">
+          <div class="timing-field timing-field-right setting-inline-right">
+            <span class="auto-delay-caption">add-phone</span>
+            <div class="auto-delay-controls">
+              <input type="number" id="input-auto-add-phone-pause-minutes" class="data-input auto-delay-input" value="10"
+                min="1" max="1440" step="1" title="遇到 add-phone / 手机号页后暂停的分钟数" />
+              <span class="data-unit">分钟</span>
+            </div>
+          </div>
+        </div>
+      </div>
       <div class="data-row">
         <span class="data-label">本地同步</span>
         <div class="data-inline auto-delay-inline">

+ 41 - 0
sidepanel/sidepanel.js

@@ -167,6 +167,7 @@ const btnCfDomainMode = document.getElementById('btn-cf-domain-mode');
 const inputRunCount = document.getElementById('input-run-count');
 const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
 const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes');
+const inputAutoAddPhonePauseMinutes = document.getElementById('input-auto-add-phone-pause-minutes');
 const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
 const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
 const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
@@ -197,6 +198,9 @@ const AUTO_DELAY_DEFAULT_MINUTES = 30;
 const AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES = 0;
 const AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES = 1440;
 const AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES = 0;
+const AUTO_ADD_PHONE_PAUSE_MIN_MINUTES = 1;
+const AUTO_ADD_PHONE_PAUSE_MAX_MINUTES = 1440;
+const AUTO_ADD_PHONE_PAUSE_DEFAULT_MINUTES = 10;
 const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
 const AUTO_STEP_DELAY_MIN_SECONDS = 0;
 const AUTO_STEP_DELAY_MAX_SECONDS = 600;
@@ -987,6 +991,23 @@ function normalizeAutoRunThreadIntervalMinutes(value) {
   );
 }
 
+function normalizeAddPhonePauseMinutes(value) {
+  const rawValue = String(value ?? '').trim();
+  if (!rawValue) {
+    return AUTO_ADD_PHONE_PAUSE_DEFAULT_MINUTES;
+  }
+
+  const numeric = Number(rawValue);
+  if (!Number.isFinite(numeric)) {
+    return AUTO_ADD_PHONE_PAUSE_DEFAULT_MINUTES;
+  }
+
+  return Math.min(
+    AUTO_ADD_PHONE_PAUSE_MAX_MINUTES,
+    Math.max(AUTO_ADD_PHONE_PAUSE_MIN_MINUTES, Math.floor(numeric))
+  );
+}
+
 function normalizeAutoStepDelaySeconds(value) {
   const rawValue = String(value ?? '').trim();
   if (!rawValue) {
@@ -1353,6 +1374,7 @@ function collectSettingsPayload() {
     cloudflareTempEmailDomains: tempEmailDomains,
     autoRunSkipFailures: inputAutoSkipFailures.checked,
     autoRunFallbackThreadIntervalMinutes: normalizeAutoRunThreadIntervalMinutes(inputAutoSkipFailuresThreadIntervalMinutes.value),
+    autoRunAddPhonePauseMinutes: normalizeAddPhonePauseMinutes(inputAutoAddPhonePauseMinutes?.value),
     autoRunDelayEnabled: inputAutoDelayEnabled.checked,
     autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
     autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
@@ -1751,6 +1773,9 @@ function applySettingsState(state) {
   setCloudflareTempEmailDomainEditMode(false, { clearInput: true });
   inputAutoSkipFailures.checked = Boolean(state?.autoRunSkipFailures);
   inputAutoSkipFailuresThreadIntervalMinutes.value = String(normalizeAutoRunThreadIntervalMinutes(state?.autoRunFallbackThreadIntervalMinutes));
+  if (inputAutoAddPhonePauseMinutes) {
+    inputAutoAddPhonePauseMinutes.value = String(normalizeAddPhonePauseMinutes(state?.autoRunAddPhonePauseMinutes));
+  }
   inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
   inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
   inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
@@ -3826,6 +3851,17 @@ inputAutoSkipFailuresThreadIntervalMinutes.addEventListener('blur', () => {
   saveSettings({ silent: true }).catch(() => { });
 });
 
+inputAutoAddPhonePauseMinutes?.addEventListener('input', () => {
+  markSettingsDirty(true);
+  scheduleSettingsAutoSave();
+});
+inputAutoAddPhonePauseMinutes?.addEventListener('blur', () => {
+  inputAutoAddPhonePauseMinutes.value = String(
+    normalizeAddPhonePauseMinutes(inputAutoAddPhonePauseMinutes.value)
+  );
+  saveSettings({ silent: true }).catch(() => { });
+});
+
 inputAutoDelayEnabled.addEventListener('change', () => {
   updateAutoDelayInputState();
   markSettingsDirty(true);
@@ -4078,6 +4114,11 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
         );
         updateFallbackThreadIntervalInputState();
       }
+      if (message.payload.autoRunAddPhonePauseMinutes !== undefined && inputAutoAddPhonePauseMinutes) {
+        inputAutoAddPhonePauseMinutes.value = String(
+          normalizeAddPhonePauseMinutes(message.payload.autoRunAddPhonePauseMinutes)
+        );
+      }
       if (message.payload.autoStepDelaySeconds !== undefined) {
         inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(message.payload.autoStepDelaySeconds);
       }

+ 12 - 1
tests/background-account-history-settings.test.js

@@ -56,14 +56,17 @@ test('background account history settings are normalized independently from hotm
     extractFunction('normalizePersistentSettingValue'),
   ].join('\n');
 
-  const api = new Function(`
+const api = new Function(`
 const DEFAULT_HOTMAIL_LOCAL_BASE_URL = 'http://127.0.0.1:17373';
 const DEFAULT_ACCOUNT_RUN_HISTORY_HELPER_BASE_URL = DEFAULT_HOTMAIL_LOCAL_BASE_URL;
 const DEFAULT_HOTMAIL_REMOTE_BASE_URL = '';
 const DEFAULT_VERIFICATION_RESEND_COUNT = 4;
+const DEFAULT_ADD_PHONE_PAUSE_MINUTES = 10;
 const DEFAULT_SUB2API_PROXY_NAME = 'shadowrocket';
 const HOTMAIL_SERVICE_MODE_REMOTE = 'remote';
 const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
+const AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES = 1;
+const AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES = 1440;
 const VERIFICATION_RESEND_COUNT_MIN = 0;
 const VERIFICATION_RESEND_COUNT_MAX = 20;
 const PERSISTED_SETTING_DEFAULTS = {
@@ -73,6 +76,12 @@ const PERSISTED_SETTING_DEFAULTS = {
 function normalizePanelMode(value) { return value === 'sub2api' ? 'sub2api' : 'cpa'; }
 function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
 function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
+function normalizeAddPhonePauseMinutes(value, fallback = DEFAULT_ADD_PHONE_PAUSE_MINUTES) {
+  const numeric = Number(value);
+  return Number.isFinite(numeric)
+    ? Math.min(AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES, Math.max(AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES, Math.floor(numeric)))
+    : fallback;
+}
 function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
 function normalizeAutoStepDelaySeconds(value) { return value == null || value === '' ? null : Number(value); }
 function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
@@ -98,6 +107,8 @@ return {
   assert.equal(api.normalizePersistentSettingValue('accountRunHistoryTextEnabled', 1), true);
   assert.equal(api.normalizePersistentSettingValue('verificationResendCount', '7'), 7);
   assert.equal(api.normalizePersistentSettingValue('verificationResendCount', '-1'), 0);
+  assert.equal(api.normalizePersistentSettingValue('autoRunAddPhonePauseMinutes', '10'), 10);
+  assert.equal(api.normalizePersistentSettingValue('autoRunAddPhonePauseMinutes', '5'), 5);
   assert.equal(
     api.normalizePersistentSettingValue('accountRunHistoryHelperBaseUrl', 'http://127.0.0.1:17373/append-account-log'),
     'http://127.0.0.1:17373'

+ 10 - 0
tests/background-icloud.test.js

@@ -68,6 +68,9 @@ const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
 const DEFAULT_HOTMAIL_REMOTE_BASE_URL = '';
 const DEFAULT_HOTMAIL_LOCAL_BASE_URL = 'http://127.0.0.1:17373';
 const DEFAULT_VERIFICATION_RESEND_COUNT = 4;
+const DEFAULT_ADD_PHONE_PAUSE_MINUTES = 10;
+const AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES = 1;
+const AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES = 1440;
 const VERIFICATION_RESEND_COUNT_MIN = 0;
 const VERIFICATION_RESEND_COUNT_MAX = 20;
 const PERSISTED_SETTING_DEFAULTS = {
@@ -95,6 +98,12 @@ function normalizeMailProvider(value = '') {
 function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
   return Math.max(0, Math.floor(Number(value) || 0));
 }
+function normalizeAddPhonePauseMinutes(value, fallback = DEFAULT_ADD_PHONE_PAUSE_MINUTES) {
+  const numeric = Number(value);
+  return Number.isFinite(numeric)
+    ? Math.min(AUTO_RUN_ADD_PHONE_PAUSE_MAX_MINUTES, Math.max(AUTO_RUN_ADD_PHONE_PAUSE_MIN_MINUTES, Math.floor(numeric)))
+    : fallback;
+}
 function normalizeAutoRunDelayMinutes(value) {
   return Math.max(1, Math.floor(Number(value) || 30));
 }
@@ -179,6 +188,7 @@ test('normalizePersistentSettingValue handles icloud settings', () => {
   assert.equal(api.normalizePersistentSettingValue('icloudHostPreference', 'icloud.com'), 'icloud.com');
   assert.equal(api.normalizePersistentSettingValue('icloudHostPreference', 'bad-host'), 'auto');
   assert.equal(api.normalizePersistentSettingValue('autoDeleteUsedIcloudAlias', 1), true);
+  assert.equal(api.normalizePersistentSettingValue('autoRunAddPhonePauseMinutes', '60'), 60);
   assert.equal(api.normalizePersistentSettingValue('verificationResendCount', '6'), 6);
   assert.equal(api.normalizePersistentSettingValue('verificationResendCount', 99), 20);
   assert.equal(api.normalizePersistentSettingValue('cloudflareTempEmailReceiveMailbox', ' Forward@Example.com '), 'forward@example.com');