完善自动注册代理和状态恢复
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from collections.abc import Mapping
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ def register_huya_with_sms_line(
|
|||||||
change_password: bool = True,
|
change_password: bool = True,
|
||||||
password_prefix: str = "hy",
|
password_prefix: str = "hy",
|
||||||
fixed_password: str = "",
|
fixed_password: str = "",
|
||||||
|
proxies: Mapping[str, str] | None = None,
|
||||||
stop_event: threading.Event | None = None,
|
stop_event: threading.Event | None = None,
|
||||||
) -> HuyaAutoRegisterResult:
|
) -> HuyaAutoRegisterResult:
|
||||||
"""使用固定手机号和接码地址完成虎牙短信注册/登录。"""
|
"""使用固定手机号和接码地址完成虎牙短信注册/登录。"""
|
||||||
@@ -76,7 +78,7 @@ def register_huya_with_sms_line(
|
|||||||
|
|
||||||
sent_at = datetime.now()
|
sent_at = datetime.now()
|
||||||
try:
|
try:
|
||||||
code_result = send_huya_sms_code(phone=phone)
|
code_result = send_huya_sms_code(phone=phone, proxies=proxies)
|
||||||
except HuyaLoginError as exc:
|
except HuyaLoginError as exc:
|
||||||
return HuyaAutoRegisterResult(
|
return HuyaAutoRegisterResult(
|
||||||
phone=phone,
|
phone=phone,
|
||||||
@@ -138,6 +140,7 @@ def register_huya_with_sms_line(
|
|||||||
authcode=poll_result.code,
|
authcode=poll_result.code,
|
||||||
state=code_result.state,
|
state=code_result.state,
|
||||||
phone=phone,
|
phone=phone,
|
||||||
|
proxies=proxies,
|
||||||
)
|
)
|
||||||
except HuyaLoginError as exc:
|
except HuyaLoginError as exc:
|
||||||
return HuyaAutoRegisterResult(
|
return HuyaAutoRegisterResult(
|
||||||
@@ -213,6 +216,7 @@ def register_huya_with_sms_line(
|
|||||||
wait_seconds=wait_seconds,
|
wait_seconds=wait_seconds,
|
||||||
poll_interval=poll_interval,
|
poll_interval=poll_interval,
|
||||||
ignore_codes={poll_result.code},
|
ignore_codes={poll_result.code},
|
||||||
|
proxies=proxies,
|
||||||
stop_event=stop_event,
|
stop_event=stop_event,
|
||||||
)
|
)
|
||||||
if not change_result.success:
|
if not change_result.success:
|
||||||
|
|||||||
@@ -458,10 +458,11 @@ def change_huya_password_with_sms_line(
|
|||||||
wait_seconds: float = 180,
|
wait_seconds: float = 180,
|
||||||
poll_interval: float = 5,
|
poll_interval: float = 5,
|
||||||
ignore_codes: set[str] | None = None,
|
ignore_codes: set[str] | None = None,
|
||||||
|
proxies: Mapping[str, str] | None = None,
|
||||||
stop_event: threading.Event | None = None,
|
stop_event: threading.Event | None = None,
|
||||||
) -> HuyaChangePasswordResult:
|
) -> HuyaChangePasswordResult:
|
||||||
"""使用同一手机号接码链接完成改密短信验证。"""
|
"""使用同一手机号接码链接完成改密短信验证。"""
|
||||||
changer = HuyaPasswordChanger(uid=uid, cookie=cookie)
|
changer = HuyaPasswordChanger(uid=uid, cookie=cookie, proxies=proxies)
|
||||||
sent_at = datetime.now()
|
sent_at = datetime.now()
|
||||||
code_result = changer.send_code()
|
code_result = changer.send_code()
|
||||||
if not code_result.success or not code_result.session_data:
|
if not code_result.success or not code_result.session_data:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from core.sms_provider import parse_sms_lines
|
|||||||
|
|
||||||
from ..database import SessionLocal, get_db
|
from ..database import SessionLocal, get_db
|
||||||
from ..deps import authenticate_websocket, get_current_user, require_permission
|
from ..deps import authenticate_websocket, get_current_user, require_permission
|
||||||
from ..models import HuyaAccount, HuyaConfig, HuyaGoodsSnapshot, HuyaRechargeGoodsSnapshot, HuyaTask, User
|
from ..models import HuyaAccount, HuyaConfig, HuyaGoodsSnapshot, HuyaRechargeGoodsSnapshot, HuyaTask, ProxyConfig, User
|
||||||
from ..permissions import user_has_permission
|
from ..permissions import user_has_permission
|
||||||
from ..schemas import (
|
from ..schemas import (
|
||||||
AccountAssign,
|
AccountAssign,
|
||||||
@@ -344,6 +344,7 @@ def sms_login_account(
|
|||||||
@router.post("/register/batches", response_model=HuyaAutoRegisterBatchOut)
|
@router.post("/register/batches", response_model=HuyaAutoRegisterBatchOut)
|
||||||
def create_auto_register_batch(
|
def create_auto_register_batch(
|
||||||
req: HuyaAutoRegisterRequest,
|
req: HuyaAutoRegisterRequest,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
current: User = Depends(get_current_user),
|
current: User = Depends(get_current_user),
|
||||||
):
|
):
|
||||||
"""启动虎牙手机号自动注册批次。"""
|
"""启动虎牙手机号自动注册批次。"""
|
||||||
@@ -352,6 +353,7 @@ def create_auto_register_batch(
|
|||||||
if not sms_lines:
|
if not sms_lines:
|
||||||
raise HTTPException(status_code=400, detail="没有识别到有效手机号,格式为:手机号----短信查询URL")
|
raise HTTPException(status_code=400, detail="没有识别到有效手机号,格式为:手机号----短信查询URL")
|
||||||
|
|
||||||
|
proxy_config = db.query(ProxyConfig).first() if req.use_proxy else None
|
||||||
runner = huya_register_registry.create(
|
runner = huya_register_registry.create(
|
||||||
sms_lines=sms_lines,
|
sms_lines=sms_lines,
|
||||||
tag=req.tag.strip(),
|
tag=req.tag.strip(),
|
||||||
@@ -361,6 +363,8 @@ def create_auto_register_batch(
|
|||||||
poll_interval=req.poll_interval,
|
poll_interval=req.poll_interval,
|
||||||
password_prefix=req.password_prefix,
|
password_prefix=req.password_prefix,
|
||||||
fixed_password=req.fixed_password,
|
fixed_password=req.fixed_password,
|
||||||
|
use_proxy=req.use_proxy,
|
||||||
|
proxy_config=proxy_config,
|
||||||
)
|
)
|
||||||
thread = threading.Thread(target=runner.run, daemon=True)
|
thread = threading.Thread(target=runner.run, daemon=True)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ class HuyaAutoRegisterRequest(BaseModel):
|
|||||||
poll_interval: float = Field(5, ge=1, le=30)
|
poll_interval: float = Field(5, ge=1, le=30)
|
||||||
password_prefix: str = Field("hy", max_length=8)
|
password_prefix: str = Field("hy", max_length=8)
|
||||||
fixed_password: str = Field("", max_length=64)
|
fixed_password: str = Field("", max_length=64)
|
||||||
|
use_proxy: bool = False
|
||||||
|
|
||||||
|
|
||||||
class HuyaAutoRegisterItemOut(BaseModel):
|
class HuyaAutoRegisterItemOut(BaseModel):
|
||||||
@@ -240,6 +241,7 @@ class HuyaAutoRegisterBatchOut(BaseModel):
|
|||||||
wait_seconds: float
|
wait_seconds: float
|
||||||
poll_interval: float
|
poll_interval: float
|
||||||
password_prefix: str = "hy"
|
password_prefix: str = "hy"
|
||||||
|
use_proxy: bool = False
|
||||||
total: int
|
total: int
|
||||||
success_count: int
|
success_count: int
|
||||||
failed_count: int
|
failed_count: int
|
||||||
|
|||||||
@@ -7,12 +7,15 @@ import uuid
|
|||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from core.douyu.proxy_fetcher import ProxyFetcher
|
||||||
from core.huya.auto_register import HuyaAutoRegisterResult, register_huya_with_sms_line
|
from core.huya.auto_register import HuyaAutoRegisterResult, register_huya_with_sms_line
|
||||||
from core.huya.cookie_utils import normalize_huya_cookie
|
from core.huya.cookie_utils import normalize_huya_cookie
|
||||||
from core.sms_provider import SmsLine
|
from core.sms_provider import SmsLine
|
||||||
|
|
||||||
from ..database import SessionLocal
|
from ..database import SessionLocal
|
||||||
|
from ..models import ProxyConfig as ProxyConfigModel
|
||||||
from .huya_service import upsert_huya_cookie
|
from .huya_service import upsert_huya_cookie
|
||||||
|
|
||||||
|
|
||||||
@@ -88,6 +91,7 @@ class HuyaRegisterBatch:
|
|||||||
items: list[HuyaRegisterItemState]
|
items: list[HuyaRegisterItemState]
|
||||||
password_prefix: str = "hy"
|
password_prefix: str = "hy"
|
||||||
fixed_password: str = ""
|
fixed_password: str = ""
|
||||||
|
use_proxy: bool = False
|
||||||
status: str = "pending"
|
status: str = "pending"
|
||||||
message: str = "等待开始"
|
message: str = "等待开始"
|
||||||
created_at: datetime = field(default_factory=_now)
|
created_at: datetime = field(default_factory=_now)
|
||||||
@@ -102,11 +106,39 @@ class HuyaRegisterRunner:
|
|||||||
self,
|
self,
|
||||||
batch: HuyaRegisterBatch,
|
batch: HuyaRegisterBatch,
|
||||||
sms_lines: list[SmsLine],
|
sms_lines: list[SmsLine],
|
||||||
|
proxy_config: Optional[ProxyConfigModel] = None,
|
||||||
):
|
):
|
||||||
self.batch = batch
|
self.batch = batch
|
||||||
self.sms_lines = sms_lines
|
self.sms_lines = sms_lines
|
||||||
|
self.proxy_config = proxy_config
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
self._stop = threading.Event()
|
self._stop = threading.Event()
|
||||||
|
self._shared_proxy_fetcher = self._create_proxy_fetcher()
|
||||||
|
|
||||||
|
def _create_proxy_fetcher(self) -> ProxyFetcher | None:
|
||||||
|
"""按需创建 API 代理获取器。"""
|
||||||
|
if not self.batch.use_proxy or not self.proxy_config or not self.proxy_config.enabled:
|
||||||
|
return None
|
||||||
|
if not self.proxy_config.api_url:
|
||||||
|
return None
|
||||||
|
|
||||||
|
wl_platform = "xiequ"
|
||||||
|
wl_credentials = None
|
||||||
|
if self.proxy_config.whitelist_enabled:
|
||||||
|
wl_platform = getattr(self.proxy_config, "whitelist_platform", None) or "xiequ"
|
||||||
|
wl_credentials = getattr(self.proxy_config, "whitelist_credentials", None)
|
||||||
|
if not wl_credentials and self.proxy_config.whitelist_uid and self.proxy_config.whitelist_ukey:
|
||||||
|
wl_credentials = {
|
||||||
|
"uid": self.proxy_config.whitelist_uid,
|
||||||
|
"ukey": self.proxy_config.whitelist_ukey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProxyFetcher(
|
||||||
|
api_url=self.proxy_config.api_url,
|
||||||
|
whitelist_platform=wl_platform,
|
||||||
|
whitelist_credentials=wl_credentials,
|
||||||
|
stop_event=self._stop,
|
||||||
|
)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self._stop.set()
|
self._stop.set()
|
||||||
@@ -131,6 +163,7 @@ class HuyaRegisterRunner:
|
|||||||
"wait_seconds": self.batch.wait_seconds,
|
"wait_seconds": self.batch.wait_seconds,
|
||||||
"poll_interval": self.batch.poll_interval,
|
"poll_interval": self.batch.poll_interval,
|
||||||
"password_prefix": self.batch.password_prefix,
|
"password_prefix": self.batch.password_prefix,
|
||||||
|
"use_proxy": self.batch.use_proxy,
|
||||||
"total": total,
|
"total": total,
|
||||||
"success_count": success,
|
"success_count": success,
|
||||||
"failed_count": failed,
|
"failed_count": failed,
|
||||||
@@ -166,11 +199,35 @@ class HuyaRegisterRunner:
|
|||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
def _resolve_proxy(self) -> tuple[dict[str, str] | None, str]:
|
||||||
|
"""为单个手机号解析代理;返回代理字典和错误消息。"""
|
||||||
|
if not self.batch.use_proxy:
|
||||||
|
return None, ""
|
||||||
|
if not self.proxy_config or not self.proxy_config.enabled:
|
||||||
|
return None, "已开启代理,但代理配置未启用"
|
||||||
|
|
||||||
|
if self.proxy_config.http or self.proxy_config.https:
|
||||||
|
proxy_url = self.proxy_config.http or self.proxy_config.https
|
||||||
|
return {"http": proxy_url, "https": proxy_url}, ""
|
||||||
|
|
||||||
|
if self._shared_proxy_fetcher:
|
||||||
|
proxy_url = self._shared_proxy_fetcher.fetch_new_proxy(max_attempts=3)
|
||||||
|
if proxy_url:
|
||||||
|
return {"http": proxy_url, "https": proxy_url}, ""
|
||||||
|
return None, "获取代理失败"
|
||||||
|
|
||||||
|
return None, "已开启代理,但未配置静态代理或代理 API"
|
||||||
|
|
||||||
def _run_one(self, index: int, item: SmsLine):
|
def _run_one(self, index: int, item: SmsLine):
|
||||||
if self._stop.is_set():
|
if self._stop.is_set():
|
||||||
self._set_item(index, status="stopped", message="已停止", finished_at=_now())
|
self._set_item(index, status="stopped", message="已停止", finished_at=_now())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
proxies, proxy_error = self._resolve_proxy()
|
||||||
|
if proxy_error:
|
||||||
|
self._set_item(index, status="error", message=proxy_error, finished_at=_now())
|
||||||
|
return
|
||||||
|
|
||||||
self._set_item(index, status="sending", message="注册并改密", started_at=_now(), finished_at=None)
|
self._set_item(index, status="sending", message="注册并改密", started_at=_now(), finished_at=None)
|
||||||
result = register_huya_with_sms_line(
|
result = register_huya_with_sms_line(
|
||||||
item,
|
item,
|
||||||
@@ -178,6 +235,7 @@ class HuyaRegisterRunner:
|
|||||||
poll_interval=self.batch.poll_interval,
|
poll_interval=self.batch.poll_interval,
|
||||||
password_prefix=self.batch.password_prefix,
|
password_prefix=self.batch.password_prefix,
|
||||||
fixed_password=self.batch.fixed_password,
|
fixed_password=self.batch.fixed_password,
|
||||||
|
proxies=proxies,
|
||||||
stop_event=self._stop,
|
stop_event=self._stop,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -236,6 +294,12 @@ class HuyaRegisterRunner:
|
|||||||
self.batch.started_at = _now()
|
self.batch.started_at = _now()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if self._shared_proxy_fetcher:
|
||||||
|
ok, msg = self._shared_proxy_fetcher.warmup_whitelist()
|
||||||
|
if not ok:
|
||||||
|
with self._lock:
|
||||||
|
self.batch.message = f"代理白名单预热失败: {msg}"
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=self.batch.concurrency) as executor:
|
with ThreadPoolExecutor(max_workers=self.batch.concurrency) as executor:
|
||||||
futures = []
|
futures = []
|
||||||
for index, item in enumerate(self.sms_lines):
|
for index, item in enumerate(self.sms_lines):
|
||||||
@@ -280,6 +344,8 @@ class HuyaRegisterRegistry:
|
|||||||
poll_interval: float,
|
poll_interval: float,
|
||||||
password_prefix: str = "hy",
|
password_prefix: str = "hy",
|
||||||
fixed_password: str = "",
|
fixed_password: str = "",
|
||||||
|
use_proxy: bool = False,
|
||||||
|
proxy_config: Optional[ProxyConfigModel] = None,
|
||||||
) -> HuyaRegisterRunner:
|
) -> HuyaRegisterRunner:
|
||||||
batch_id = uuid.uuid4().hex[:12]
|
batch_id = uuid.uuid4().hex[:12]
|
||||||
batch = HuyaRegisterBatch(
|
batch = HuyaRegisterBatch(
|
||||||
@@ -291,12 +357,13 @@ class HuyaRegisterRegistry:
|
|||||||
poll_interval=max(1.0, float(poll_interval or 5)),
|
poll_interval=max(1.0, float(poll_interval or 5)),
|
||||||
password_prefix=(password_prefix or "hy").strip()[:8] or "hy",
|
password_prefix=(password_prefix or "hy").strip()[:8] or "hy",
|
||||||
fixed_password=(fixed_password or "").strip(),
|
fixed_password=(fixed_password or "").strip(),
|
||||||
|
use_proxy=bool(use_proxy),
|
||||||
items=[
|
items=[
|
||||||
HuyaRegisterItemState(line=index + 1, phone=item.phone, provider=item.provider, sms_url=item.url)
|
HuyaRegisterItemState(line=index + 1, phone=item.phone, provider=item.provider, sms_url=item.url)
|
||||||
for index, item in enumerate(sms_lines)
|
for index, item in enumerate(sms_lines)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
runner = HuyaRegisterRunner(batch=batch, sms_lines=sms_lines)
|
runner = HuyaRegisterRunner(batch=batch, sms_lines=sms_lines, proxy_config=proxy_config)
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self._runners[batch_id] = runner
|
self._runners[batch_id] = runner
|
||||||
return runner
|
return runner
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ export interface HuyaAutoRegisterRequest {
|
|||||||
poll_interval?: number;
|
poll_interval?: number;
|
||||||
password_prefix?: string;
|
password_prefix?: string;
|
||||||
fixed_password?: string;
|
fixed_password?: string;
|
||||||
|
use_proxy?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HuyaAutoRegisterItem {
|
export interface HuyaAutoRegisterItem {
|
||||||
@@ -215,6 +216,7 @@ export interface HuyaAutoRegisterBatch {
|
|||||||
wait_seconds: number;
|
wait_seconds: number;
|
||||||
poll_interval: number;
|
poll_interval: number;
|
||||||
password_prefix: string;
|
password_prefix: string;
|
||||||
|
use_proxy: boolean;
|
||||||
total: number;
|
total: number;
|
||||||
success_count: number;
|
success_count: number;
|
||||||
failed_count: number;
|
failed_count: number;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Button, Card, Col, Input, InputNumber, message, Row, Segmented, Space, Statistic, Table, Tag, Typography,
|
Button, Card, Col, Input, InputNumber, message, Row, Segmented, Space, Statistic, Switch, Table, Tag, Typography,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import type { TableProps } from 'antd';
|
import type { TableProps } from 'antd';
|
||||||
import { DownloadOutlined, PlayCircleOutlined, ReloadOutlined, StopOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, PlayCircleOutlined, ReloadOutlined, StopOutlined } from '@ant-design/icons';
|
||||||
@@ -11,6 +11,34 @@ import { getErrorMessage } from '../utils/error';
|
|||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
|
type PasswordMode = 'random' | 'fixed';
|
||||||
|
|
||||||
|
interface StoredRegisterForm {
|
||||||
|
text: string;
|
||||||
|
tag: string;
|
||||||
|
concurrency: number;
|
||||||
|
waitSeconds: number;
|
||||||
|
pollInterval: number;
|
||||||
|
passwordMode: PasswordMode;
|
||||||
|
passwordPrefix: string;
|
||||||
|
fixedPassword: string;
|
||||||
|
useProxy: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FORM_STORAGE_KEY = 'huya_auto_register_form';
|
||||||
|
const BATCH_STORAGE_KEY = 'huya_auto_register_batch_id';
|
||||||
|
const DEFAULT_FORM: StoredRegisterForm = {
|
||||||
|
text: '',
|
||||||
|
tag: '',
|
||||||
|
concurrency: 1,
|
||||||
|
waitSeconds: 180,
|
||||||
|
pollInterval: 5,
|
||||||
|
passwordMode: 'random',
|
||||||
|
passwordPrefix: 'hy',
|
||||||
|
fixedPassword: '',
|
||||||
|
useProxy: false,
|
||||||
|
};
|
||||||
|
|
||||||
const STATUS_LABELS: Record<string, string> = {
|
const STATUS_LABELS: Record<string, string> = {
|
||||||
pending: '等待',
|
pending: '等待',
|
||||||
sending: '发码',
|
sending: '发码',
|
||||||
@@ -35,35 +63,118 @@ const STATUS_COLORS: Record<string, string> = {
|
|||||||
|
|
||||||
const RUNNING_STATUS = new Set(['pending', 'running']);
|
const RUNNING_STATUS = new Set(['pending', 'running']);
|
||||||
|
|
||||||
|
function safeNumber(value: unknown, fallback: number) {
|
||||||
|
const n = Number(value);
|
||||||
|
return Number.isFinite(n) ? n : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStoredForm(): StoredRegisterForm {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(FORM_STORAGE_KEY);
|
||||||
|
if (!raw) return DEFAULT_FORM;
|
||||||
|
const parsed = JSON.parse(raw) as Partial<StoredRegisterForm>;
|
||||||
|
const passwordMode = parsed.passwordMode === 'fixed' ? 'fixed' : 'random';
|
||||||
|
return {
|
||||||
|
...DEFAULT_FORM,
|
||||||
|
...parsed,
|
||||||
|
concurrency: safeNumber(parsed.concurrency, DEFAULT_FORM.concurrency),
|
||||||
|
waitSeconds: safeNumber(parsed.waitSeconds, DEFAULT_FORM.waitSeconds),
|
||||||
|
pollInterval: safeNumber(parsed.pollInterval, DEFAULT_FORM.pollInterval),
|
||||||
|
passwordMode,
|
||||||
|
useProxy: Boolean(parsed.useProxy),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return DEFAULT_FORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStoredBatchId() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(BATCH_STORAGE_KEY) || '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function HuyaRegisterPage() {
|
export default function HuyaRegisterPage() {
|
||||||
const [text, setText] = useState('');
|
const initialFormRef = useRef<StoredRegisterForm | null>(null);
|
||||||
const [tag, setTag] = useState('');
|
if (initialFormRef.current === null) {
|
||||||
const [concurrency, setConcurrency] = useState(1);
|
initialFormRef.current = readStoredForm();
|
||||||
const [waitSeconds, setWaitSeconds] = useState(180);
|
}
|
||||||
const [pollInterval, setPollInterval] = useState(5);
|
const initialForm = initialFormRef.current;
|
||||||
const [passwordMode, setPasswordMode] = useState<'random' | 'fixed'>('random');
|
|
||||||
const [passwordPrefix, setPasswordPrefix] = useState('hy');
|
const [text, setText] = useState(initialForm.text);
|
||||||
const [fixedPassword, setFixedPassword] = useState('');
|
const [tag, setTag] = useState(initialForm.tag);
|
||||||
|
const [concurrency, setConcurrency] = useState(initialForm.concurrency);
|
||||||
|
const [waitSeconds, setWaitSeconds] = useState(initialForm.waitSeconds);
|
||||||
|
const [pollInterval, setPollInterval] = useState(initialForm.pollInterval);
|
||||||
|
const [passwordMode, setPasswordMode] = useState<PasswordMode>(initialForm.passwordMode);
|
||||||
|
const [passwordPrefix, setPasswordPrefix] = useState(initialForm.passwordPrefix);
|
||||||
|
const [fixedPassword, setFixedPassword] = useState(initialForm.fixedPassword);
|
||||||
|
const [useProxy, setUseProxy] = useState(initialForm.useProxy);
|
||||||
const [batch, setBatch] = useState<HuyaAutoRegisterBatch | null>(null);
|
const [batch, setBatch] = useState<HuyaAutoRegisterBatch | null>(null);
|
||||||
const [starting, setStarting] = useState(false);
|
const [starting, setStarting] = useState(false);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const [stopping, setStopping] = useState(false);
|
const [stopping, setStopping] = useState(false);
|
||||||
|
const restoredBatchRef = useRef(false);
|
||||||
|
|
||||||
const batchId = batch?.batch_id || '';
|
const batchId = batch?.batch_id || '';
|
||||||
const isRunning = !!batch && RUNNING_STATUS.has(batch.status);
|
const isRunning = !!batch && RUNNING_STATUS.has(batch.status);
|
||||||
|
|
||||||
const refreshBatch = useCallback(async () => {
|
const loadBatchById = useCallback(async (id: string) => {
|
||||||
if (!batchId) return;
|
if (!id) return;
|
||||||
setRefreshing(true);
|
setRefreshing(true);
|
||||||
try {
|
try {
|
||||||
const data = await huyaApi.getAutoRegisterBatch(batchId);
|
const data = await huyaApi.getAutoRegisterBatch(id);
|
||||||
setBatch(data);
|
setBatch(data);
|
||||||
|
localStorage.setItem(BATCH_STORAGE_KEY, data.batch_id);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
message.error(getErrorMessage(e));
|
const err = getErrorMessage(e);
|
||||||
|
if (err.includes('批次不存在') || err.includes('服务已重启')) {
|
||||||
|
localStorage.removeItem(BATCH_STORAGE_KEY);
|
||||||
|
setBatch(null);
|
||||||
|
message.warning('上次自动注册批次已不存在,已清除恢复记录');
|
||||||
|
} else {
|
||||||
|
message.error(err);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
}
|
}
|
||||||
}, [batchId]);
|
}, []);
|
||||||
|
|
||||||
|
const refreshBatch = useCallback(async () => {
|
||||||
|
if (!batchId) return;
|
||||||
|
await loadBatchById(batchId);
|
||||||
|
}, [batchId, loadBatchById]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem(FORM_STORAGE_KEY, JSON.stringify({
|
||||||
|
text,
|
||||||
|
tag,
|
||||||
|
concurrency,
|
||||||
|
waitSeconds,
|
||||||
|
pollInterval,
|
||||||
|
passwordMode,
|
||||||
|
passwordPrefix,
|
||||||
|
fixedPassword,
|
||||||
|
useProxy,
|
||||||
|
}));
|
||||||
|
}, [text, tag, concurrency, waitSeconds, pollInterval, passwordMode, passwordPrefix, fixedPassword, useProxy]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (restoredBatchRef.current) return;
|
||||||
|
restoredBatchRef.current = true;
|
||||||
|
const storedBatchId = readStoredBatchId();
|
||||||
|
if (storedBatchId) {
|
||||||
|
loadBatchById(storedBatchId);
|
||||||
|
}
|
||||||
|
}, [loadBatchById]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (batch?.batch_id) {
|
||||||
|
localStorage.setItem(BATCH_STORAGE_KEY, batch.batch_id);
|
||||||
|
}
|
||||||
|
}, [batch?.batch_id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isRunning || !batchId) return undefined;
|
if (!isRunning || !batchId) return undefined;
|
||||||
@@ -97,6 +208,7 @@ export default function HuyaRegisterPage() {
|
|||||||
poll_interval: pollInterval,
|
poll_interval: pollInterval,
|
||||||
password_prefix: passwordMode === 'random' ? (passwordPrefix.trim() || 'hy') : 'hy',
|
password_prefix: passwordMode === 'random' ? (passwordPrefix.trim() || 'hy') : 'hy',
|
||||||
fixed_password: passwordMode === 'fixed' ? fixedPassword.trim() : '',
|
fixed_password: passwordMode === 'fixed' ? fixedPassword.trim() : '',
|
||||||
|
use_proxy: useProxy,
|
||||||
});
|
});
|
||||||
setBatch(data);
|
setBatch(data);
|
||||||
message.success('自动注册批次已启动');
|
message.success('自动注册批次已启动');
|
||||||
@@ -274,6 +386,18 @@ export default function HuyaRegisterPage() {
|
|||||||
)}
|
)}
|
||||||
</Space.Compact>
|
</Space.Compact>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col xs={12} md={4}>
|
||||||
|
<Text type="secondary">代理</Text>
|
||||||
|
<div style={{ height: 32, display: 'flex', alignItems: 'center' }}>
|
||||||
|
<Switch
|
||||||
|
checked={useProxy}
|
||||||
|
checkedChildren="开"
|
||||||
|
unCheckedChildren="关"
|
||||||
|
onChange={setUseProxy}
|
||||||
|
disabled={isRunning}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
<Col xs={24} md={4}>
|
<Col xs={24} md={4}>
|
||||||
<Space style={{ width: '100%', paddingTop: 22 }}>
|
<Space style={{ width: '100%', paddingTop: 22 }}>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user