Add HeroSMS free phone reuse

This commit is contained in:
initiatione
2026-05-06 18:16:59 +08:00
parent 9e6899f37c
commit b6777edbc8
13 changed files with 2170 additions and 15 deletions
+191 -1
View File
@@ -406,6 +406,9 @@ const rowPhoneCodeWaitSeconds = document.getElementById('row-phone-code-wait-sec
const rowPhoneCodeTimeoutWindows = document.getElementById('row-phone-code-timeout-windows');
const rowPhoneCodePollIntervalSeconds = document.getElementById('row-phone-code-poll-interval-seconds');
const rowPhoneCodePollMaxRounds = document.getElementById('row-phone-code-poll-max-rounds');
const rowFreePhoneReuseEnabled = document.getElementById('row-free-phone-reuse-enabled');
const rowFreePhoneReuseAutoEnabled = document.getElementById('row-free-phone-reuse-auto-enabled');
const rowFreeReusablePhone = document.getElementById('row-free-reusable-phone');
const inputHeroSmsApiKey = document.getElementById('input-hero-sms-api-key');
const btnToggleHeroSmsApiKey = document.getElementById('btn-toggle-hero-sms-api-key');
const inputFiveSimApiKey = document.getElementById('input-five-sim-api-key');
@@ -423,6 +426,9 @@ const inputPhoneCodeTimeoutWindows = document.getElementById('input-phone-code-t
const inputPhoneCodePollIntervalSeconds = document.getElementById('input-phone-code-poll-interval-seconds');
const inputPhoneCodePollMaxRounds = document.getElementById('input-phone-code-poll-max-rounds');
const inputHeroSmsReuseEnabled = document.getElementById('input-hero-sms-reuse-enabled');
const inputFreePhoneReuseEnabled = document.getElementById('input-free-phone-reuse-enabled');
const inputFreePhoneReuseAutoEnabled = document.getElementById('input-free-phone-reuse-auto-enabled');
const inputFreeReusablePhone = document.getElementById('input-free-reusable-phone');
const selectHeroSmsCountry = document.getElementById('select-hero-sms-country');
const selectHeroSmsCountryFallback = document.getElementById('select-hero-sms-country-fallback');
const selectHeroSmsAcquirePriority = document.getElementById('select-hero-sms-acquire-priority');
@@ -454,10 +460,14 @@ const displayHeroSmsCurrentCountdown = document.getElementById('display-hero-sms
const displayHeroSmsPriceTiers = document.getElementById('display-hero-sms-price-tiers');
const displayPhoneSmsBalance = document.getElementById('display-phone-sms-balance');
const displayHeroSmsCurrentCode = document.getElementById('display-hero-sms-current-code');
const displayFreeReusablePhoneCountry = document.getElementById('display-free-reusable-phone-country');
const displayFreeReusablePhone = document.getElementById('display-free-reusable-phone');
const displayHeroSmsCountryFallbackOrder = document.getElementById('display-hero-sms-country-fallback-order');
const displayFiveSimCountryFallbackOrder = document.getElementById('display-five-sim-country-fallback-order');
const displayNexSmsCountryFallbackOrder = document.getElementById('display-nex-sms-country-fallback-order');
const displayPhoneSmsProviderOrder = document.getElementById('display-phone-sms-provider-order');
const btnSaveFreeReusablePhone = document.getElementById('btn-save-free-reusable-phone');
const btnClearFreeReusablePhone = document.getElementById('btn-clear-free-reusable-phone');
const rowAccountRunHistoryHelperBaseUrl = document.getElementById('row-account-run-history-helper-base-url');
const inputAccountRunHistoryHelperBaseUrl = document.getElementById('input-account-run-history-helper-base-url');
const autoStartModal = document.getElementById('auto-start-modal');
@@ -2978,6 +2988,12 @@ function collectSettingsPayload() {
const heroSmsReuseEnabledValue = typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled
? normalizeHeroSmsReuseEnabledValue(inputHeroSmsReuseEnabled.checked)
: defaultHeroSmsReuseEnabled;
const freePhoneReuseEnabledValue = typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled
? Boolean(inputFreePhoneReuseEnabled.checked)
: Boolean(latestState?.freePhoneReuseEnabled);
const freePhoneReuseAutoEnabledValue = typeof inputFreePhoneReuseAutoEnabled !== 'undefined' && inputFreePhoneReuseAutoEnabled
? Boolean(inputFreePhoneReuseAutoEnabled.checked)
: Boolean(latestState?.freePhoneReuseAutoEnabled);
const defaultHeroSmsAcquirePriority = typeof DEFAULT_HERO_SMS_ACQUIRE_PRIORITY !== 'undefined'
? DEFAULT_HERO_SMS_ACQUIRE_PRIORITY
: (typeof HERO_SMS_ACQUIRE_PRIORITY_COUNTRY !== 'undefined' ? HERO_SMS_ACQUIRE_PRIORITY_COUNTRY : 'country');
@@ -3342,6 +3358,8 @@ function collectSettingsPayload() {
nexSmsCountryOrder: nexSmsCountryOrderValue,
nexSmsServiceCode: nexSmsServiceCodeValue,
heroSmsReuseEnabled: heroSmsReuseEnabledValue,
freePhoneReuseEnabled: freePhoneReuseEnabledValue,
freePhoneReuseAutoEnabled: freePhoneReuseAutoEnabledValue,
heroSmsAcquirePriority: heroSmsAcquirePriorityValue,
heroSmsMaxPrice: heroSmsMaxPriceValue,
heroSmsPreferredPrice: heroSmsPreferredPriceValue,
@@ -5341,10 +5359,79 @@ function updateHeroSmsRuntimeDisplay(state = {}) {
const code = String(state?.currentPhoneVerificationCode ?? latestState?.currentPhoneVerificationCode ?? '').trim();
displayHeroSmsCurrentCode.textContent = code || '未获取';
}
if (displayFreeReusablePhone || displayFreeReusablePhoneCountry || inputFreeReusablePhone) {
const activation = state?.freeReusablePhoneActivation ?? latestState?.freeReusablePhoneActivation ?? null;
const phoneNumber = String(activation?.phoneNumber || '').trim();
const activationId = String(activation?.activationId || '').trim();
const successfulUses = Number.isFinite(Number(activation?.successfulUses))
? Number(activation.successfulUses)
: null;
const maxUses = Number.isFinite(Number(activation?.maxUses))
? Number(activation.maxUses)
: null;
const countryLabel = normalizePhoneSmsCountryLabel(
activation?.countryLabel
|| getHeroSmsCountryLabelById(activation?.countryId || '')
|| state?.heroSmsCountryLabel
|| latestState?.heroSmsCountryLabel
|| getHeroSmsCountryLabelById(state?.heroSmsCountryId || latestState?.heroSmsCountryId || ''),
activation?.provider || getSelectedPhoneSmsProvider()
);
const usesText = successfulUses !== null || maxUses !== null
? ` / ${successfulUses ?? 0}/${maxUses ?? 3}`
: '';
if (displayFreeReusablePhone) {
displayFreeReusablePhone.textContent = phoneNumber
? `${phoneNumber}${activationId ? ` (#${activationId})` : ''}${usesText}`
: '未保存';
}
if (displayFreeReusablePhoneCountry) {
displayFreeReusablePhoneCountry.textContent = phoneNumber
? `地区:${countryLabel || '未保存'}`
: '地区:未保存';
}
if (inputFreeReusablePhone) {
inputFreeReusablePhone.value = phoneNumber;
}
}
syncPhoneRuntimeCountdown(state);
renderPhonePreferredActivationOptions(state);
}
function applyFreeReusablePhoneMutationResult(refreshedState = {}, mutationResult = {}, options = {}) {
const { clear = false } = options;
const explicitActivation = clear
? null
: (
mutationResult?.freeReusablePhoneActivation
|| mutationResult?.state?.freeReusablePhoneActivation
|| null
);
const statePatch = {
...(refreshedState || {}),
...(mutationResult?.state || {}),
...(clear || explicitActivation
? { freeReusablePhoneActivation: explicitActivation }
: {}),
};
syncLatestState(statePatch);
updateHeroSmsRuntimeDisplay(latestState || statePatch);
}
async function refreshFreeReusablePhoneStateFallback(mutationResult = {}, options = {}) {
if (mutationResult?.state || mutationResult?.freeReusablePhoneActivation || options.clear) {
applyFreeReusablePhoneMutationResult(latestState, mutationResult, options);
return;
}
try {
const refreshedState = await chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' });
applyFreeReusablePhoneMutationResult(refreshedState || latestState, mutationResult, options);
} catch (error) {
console.warn('Failed to refresh free reusable phone state:', error);
applyFreeReusablePhoneMutationResult(latestState, mutationResult, options);
}
}
async function loadHeroSmsCountries() {
const countrySelect = selectHeroSmsCountry || selectHeroSmsCountryFallback;
if (!countrySelect) {
@@ -6948,6 +7035,8 @@ function updatePhoneVerificationSettingsUI() {
typeof rowPhoneCodeTimeoutWindows !== 'undefined' ? rowPhoneCodeTimeoutWindows : null,
typeof rowPhoneCodePollIntervalSeconds !== 'undefined' ? rowPhoneCodePollIntervalSeconds : null,
typeof rowPhoneCodePollMaxRounds !== 'undefined' ? rowPhoneCodePollMaxRounds : null,
typeof rowFreePhoneReuseEnabled !== 'undefined' ? rowFreePhoneReuseEnabled : null,
typeof rowFreePhoneReuseAutoEnabled !== 'undefined' ? rowFreePhoneReuseAutoEnabled : null,
];
phoneVerificationRows.forEach((row) => {
if (row) {
@@ -6970,12 +7059,33 @@ function updatePhoneVerificationSettingsUI() {
if (rowFiveSimOperator) {
rowFiveSimOperator.style.display = showSettings && fiveSimProvider ? '' : 'none';
}
if (typeof rowFreePhoneReuseEnabled !== 'undefined' && rowFreePhoneReuseEnabled) {
rowFreePhoneReuseEnabled.style.display = showSettings ? '' : 'none';
}
if (typeof rowFreePhoneReuseAutoEnabled !== 'undefined' && rowFreePhoneReuseAutoEnabled) {
rowFreePhoneReuseAutoEnabled.style.display = showSettings ? '' : 'none';
}
const freePhoneReuseEnabled = Boolean(
typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled?.checked
);
const freePhoneReuseAutoAvailable = showSettings && freePhoneReuseEnabled;
if (typeof inputFreePhoneReuseAutoEnabled !== 'undefined' && inputFreePhoneReuseAutoEnabled) {
inputFreePhoneReuseAutoEnabled.disabled = !freePhoneReuseAutoAvailable;
if (!freePhoneReuseAutoAvailable) {
inputFreePhoneReuseAutoEnabled.checked = false;
}
}
setFreePhoneReuseControlsLocked(isAutoRunLockedPhase() || isAutoRunScheduledPhase());
if (typeof rowFreePhoneReuseAutoEnabled !== 'undefined' && rowFreePhoneReuseAutoEnabled) {
rowFreePhoneReuseAutoEnabled.classList.toggle('is-disabled', !freePhoneReuseAutoAvailable);
}
const runtimeVisible = enabled;
[
typeof rowHeroSmsRuntimePair !== 'undefined' ? rowHeroSmsRuntimePair : null,
typeof rowHeroSmsCurrentNumber !== 'undefined' ? rowHeroSmsCurrentNumber : null,
typeof rowHeroSmsCurrentCountdown !== 'undefined' ? rowHeroSmsCurrentCountdown : null,
typeof rowHeroSmsCurrentCode !== 'undefined' ? rowHeroSmsCurrentCode : null,
typeof rowFreeReusablePhone !== 'undefined' ? rowFreeReusablePhone : null,
typeof rowHeroSmsPreferredActivation !== 'undefined' ? rowHeroSmsPreferredActivation : null,
].forEach((row) => {
if (row) {
@@ -7097,6 +7207,17 @@ function setSettingsCardLocked(locked) {
});
}
function setFreePhoneReuseControlsLocked(locked) {
if (inputFreePhoneReuseEnabled) {
inputFreePhoneReuseEnabled.disabled = locked;
}
if (inputFreePhoneReuseAutoEnabled) {
inputFreePhoneReuseAutoEnabled.disabled = locked
|| !Boolean(inputFreePhoneReuseEnabled?.checked)
|| !Boolean(inputPhoneVerificationEnabled?.checked && phoneVerificationSectionExpanded);
}
}
async function setRuntimeEmailState(email) {
const normalizedEmail = String(email || '').trim() || null;
const response = await chrome.runtime.sendMessage({
@@ -7536,6 +7657,7 @@ function applyAutoRunStatus(payload = currentAutoRun) {
const settingsCardLocked = scheduled || locked;
setSettingsCardLocked(settingsCardLocked);
setFreePhoneReuseControlsLocked(settingsCardLocked);
inputRunCount.disabled = currentAutoRun.autoRunning || (
typeof shouldLockRunCountToEmailPool === 'function'
@@ -8092,6 +8214,12 @@ function applySettingsState(state) {
if (typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled) {
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(state?.heroSmsReuseEnabled);
}
if (typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled) {
inputFreePhoneReuseEnabled.checked = Boolean(state?.freePhoneReuseEnabled);
}
if (typeof inputFreePhoneReuseAutoEnabled !== 'undefined' && inputFreePhoneReuseAutoEnabled) {
inputFreePhoneReuseAutoEnabled.checked = Boolean(state?.freePhoneReuseAutoEnabled);
}
if (typeof selectHeroSmsAcquirePriority !== 'undefined' && selectHeroSmsAcquirePriority) {
selectHeroSmsAcquirePriority.value = normalizeHeroSmsAcquirePriority(state?.heroSmsAcquirePriority);
}
@@ -12419,6 +12547,59 @@ inputHeroSmsReuseEnabled?.addEventListener('change', () => {
saveSettings({ silent: true }).catch(() => { });
});
inputFreePhoneReuseEnabled?.addEventListener('change', () => {
if (!inputFreePhoneReuseEnabled.checked && inputFreePhoneReuseAutoEnabled) {
inputFreePhoneReuseAutoEnabled.checked = false;
}
updatePhoneVerificationSettingsUI();
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
inputFreePhoneReuseAutoEnabled?.addEventListener('change', () => {
updatePhoneVerificationSettingsUI();
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
btnSaveFreeReusablePhone?.addEventListener('click', async () => {
const phoneNumber = String(inputFreeReusablePhone?.value || '').trim();
if (!phoneNumber) {
showToast?.('请先填写白嫖复用手机号。', 'warn', 2200);
inputFreeReusablePhone?.focus?.();
return;
}
try {
const response = await chrome.runtime.sendMessage({
type: 'SET_FREE_REUSABLE_PHONE', payload: { phoneNumber },
});
if (response?.error) {
throw new Error(response.error);
}
await refreshFreeReusablePhoneStateFallback(response || {});
showToast?.('已记录白嫖复用手机号。', 'success', 1800);
} catch (error) {
console.error('Failed to save free reusable phone:', error);
showToast?.(`记录白嫖复用手机号失败:${error?.message || error}`, 'error', 4000);
}
});
btnClearFreeReusablePhone?.addEventListener('click', async () => {
try {
const response = await chrome.runtime.sendMessage({
type: 'CLEAR_FREE_REUSABLE_PHONE',
});
if (response?.error) {
throw new Error(response.error);
}
await refreshFreeReusablePhoneStateFallback(response || {}, { clear: true });
showToast?.('已清除白嫖复用手机号。', 'info', 1800);
} catch (error) {
console.error('Failed to clear free reusable phone:', error);
showToast?.(`清除白嫖复用手机号失败:${error?.message || error}`, 'error', 4000);
}
});
selectHeroSmsAcquirePriority?.addEventListener('change', () => {
selectHeroSmsAcquirePriority.value = normalizeHeroSmsAcquirePriority(selectHeroSmsAcquirePriority.value);
markSettingsDirty(true);
@@ -13243,6 +13424,14 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.payload.heroSmsReuseEnabled !== undefined && inputHeroSmsReuseEnabled) {
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(message.payload.heroSmsReuseEnabled);
}
if (message.payload.freePhoneReuseEnabled !== undefined && inputFreePhoneReuseEnabled) {
inputFreePhoneReuseEnabled.checked = Boolean(message.payload.freePhoneReuseEnabled);
updatePhoneVerificationSettingsUI();
}
if (message.payload.freePhoneReuseAutoEnabled !== undefined && inputFreePhoneReuseAutoEnabled) {
inputFreePhoneReuseAutoEnabled.checked = Boolean(message.payload.freePhoneReuseAutoEnabled);
updatePhoneVerificationSettingsUI();
}
if (message.payload.heroSmsAcquirePriority !== undefined && selectHeroSmsAcquirePriority) {
selectHeroSmsAcquirePriority.value = normalizeHeroSmsAcquirePriority(message.payload.heroSmsAcquirePriority);
}
@@ -13397,7 +13586,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
: latestState?.heroSmsCountryFallback
);
applyHeroSmsFallbackSelection(
[...nextPrimaryCountries, ...nextFallback],
[nextPrimary, ...nextFallback],
{ includePrimary: true }
);
updateHeroSmsPlatformDisplay();
@@ -13411,6 +13600,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|| message.payload.currentPhoneVerificationCountdownEndsAt !== undefined
|| message.payload.currentPhoneVerificationCountdownWindowIndex !== undefined
|| message.payload.currentPhoneVerificationCountdownWindowTotal !== undefined
|| message.payload.freeReusablePhoneActivation !== undefined
|| message.payload.heroSmsLastPriceTiers !== undefined
|| message.payload.heroSmsLastPriceCountryId !== undefined
|| message.payload.heroSmsLastPriceCountryLabel !== undefined