新增电竞手册独立绑定流程
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"""新增斗鱼电竞手册配置
|
||||
|
||||
Revision ID: 20260728_0010
|
||||
Revises: 20260725_0009
|
||||
Create Date: 2026-07-28
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = "20260728_0010"
|
||||
down_revision: Union[str, None] = "20260725_0009"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def _columns(bind, table_name: str) -> set[str]:
|
||||
if not sa.inspect(bind).has_table(table_name):
|
||||
return set()
|
||||
return {column["name"] for column in sa.inspect(bind).get_columns(table_name)}
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
config_columns = _columns(bind, "douyu_config")
|
||||
for column in [
|
||||
sa.Column("esports_manual_id", sa.String(length=64), nullable=True),
|
||||
sa.Column("esports_act_alias", sa.String(length=64), nullable=True),
|
||||
sa.Column("esports_amount", sa.Integer(), nullable=True),
|
||||
]:
|
||||
if column.name not in config_columns:
|
||||
op.add_column("douyu_config", column)
|
||||
|
||||
account_columns = _columns(bind, "accounts")
|
||||
for column in [
|
||||
sa.Column("esports_points", sa.Integer(), nullable=True),
|
||||
sa.Column("esports_game_name", sa.String(length=128), nullable=True),
|
||||
sa.Column("esports_game_channel", sa.String(length=128), nullable=True),
|
||||
sa.Column("esports_bind_status", sa.String(length=32), nullable=True),
|
||||
sa.Column("esports_change_role_wait_time", sa.Integer(), nullable=True),
|
||||
]:
|
||||
if column.name not in account_columns:
|
||||
op.add_column("accounts", column)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
account_columns = _columns(bind, "accounts")
|
||||
for column_name in [
|
||||
"esports_change_role_wait_time",
|
||||
"esports_bind_status",
|
||||
"esports_game_channel",
|
||||
"esports_game_name",
|
||||
"esports_points",
|
||||
]:
|
||||
if column_name in account_columns:
|
||||
op.drop_column("accounts", column_name)
|
||||
|
||||
config_columns = _columns(bind, "douyu_config")
|
||||
for column_name in ["esports_amount", "esports_act_alias", "esports_manual_id"]:
|
||||
if column_name in config_columns:
|
||||
op.drop_column("douyu_config", column_name)
|
||||
@@ -0,0 +1,51 @@
|
||||
"""补充电竞手册账号独立字段
|
||||
|
||||
Revision ID: 20260728_0011
|
||||
Revises: 20260728_0010
|
||||
Create Date: 2026-07-28
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = "20260728_0011"
|
||||
down_revision: Union[str, None] = "20260728_0010"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def _columns(bind, table_name: str) -> set[str]:
|
||||
if not sa.inspect(bind).has_table(table_name):
|
||||
return set()
|
||||
return {column["name"] for column in sa.inspect(bind).get_columns(table_name)}
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
columns = _columns(bind, "accounts")
|
||||
for column in [
|
||||
sa.Column("esports_points", sa.Integer(), nullable=True),
|
||||
sa.Column("esports_game_name", sa.String(length=128), nullable=True),
|
||||
sa.Column("esports_game_channel", sa.String(length=128), nullable=True),
|
||||
sa.Column("esports_bind_status", sa.String(length=32), nullable=True),
|
||||
sa.Column("esports_change_role_wait_time", sa.Integer(), nullable=True),
|
||||
]:
|
||||
if column.name not in columns:
|
||||
op.add_column("accounts", column)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
columns = _columns(bind, "accounts")
|
||||
for column_name in [
|
||||
"esports_change_role_wait_time",
|
||||
"esports_bind_status",
|
||||
"esports_game_channel",
|
||||
"esports_game_name",
|
||||
"esports_points",
|
||||
]:
|
||||
if column_name in columns:
|
||||
op.drop_column("accounts", column_name)
|
||||
@@ -64,6 +64,11 @@ class Account(Base):
|
||||
exchange_balance = Column(Integer, nullable=True)
|
||||
bind_status = Column(String(32), default="")
|
||||
change_role_wait_time = Column(Integer, nullable=True)
|
||||
esports_points = Column(Integer, nullable=True)
|
||||
esports_game_name = Column(String(128), default="")
|
||||
esports_game_channel = Column(String(128), default="")
|
||||
esports_bind_status = Column(String(32), default="")
|
||||
esports_change_role_wait_time = Column(Integer, nullable=True)
|
||||
created_at = Column(DateTime, default=_utcnow)
|
||||
updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)
|
||||
|
||||
@@ -119,6 +124,9 @@ class DouyuConfig(Base):
|
||||
legacy_act_alias = Column(String(64), default="cjm")
|
||||
room_id = Column(String(64), default="9263298")
|
||||
elite_amount = Column(Integer, default=3000)
|
||||
esports_manual_id = Column(String(64), default="1W0yGkOdDbAXb")
|
||||
esports_act_alias = Column(String(64), default="20260226ZMGDG")
|
||||
esports_amount = Column(Integer, default=3000)
|
||||
gold_pay_type = Column(Integer, default=1)
|
||||
gift_id = Column(String(64), default="23643")
|
||||
skin_id = Column(String(64), default="2942")
|
||||
|
||||
@@ -107,6 +107,11 @@ def _account_out(account: Account) -> DouyuTaskAccountOut:
|
||||
exchange_balance=account.exchange_balance,
|
||||
bind_status=account.bind_status or "",
|
||||
change_role_wait_time=account.change_role_wait_time,
|
||||
esports_points=account.esports_points,
|
||||
esports_game_name=account.esports_game_name or "",
|
||||
esports_game_channel=account.esports_game_channel or "",
|
||||
esports_bind_status=account.esports_bind_status or "",
|
||||
esports_change_role_wait_time=account.esports_change_role_wait_time,
|
||||
assigned_to=account.assigned_to,
|
||||
assigned_username=account.assigned_user.username if account.assigned_user else None,
|
||||
)
|
||||
@@ -140,6 +145,9 @@ def _config_out(config: DouyuConfig) -> DouyuConfigOut:
|
||||
legacy_act_alias=douyu_config_value("legacy_act_alias", config.legacy_act_alias),
|
||||
room_id=douyu_config_value("room_id", config.room_id),
|
||||
elite_amount=douyu_config_value("elite_amount", config.elite_amount),
|
||||
esports_manual_id=douyu_config_value("esports_manual_id", config.esports_manual_id),
|
||||
esports_act_alias=douyu_config_value("esports_act_alias", config.esports_act_alias),
|
||||
esports_amount=douyu_config_value("esports_amount", config.esports_amount),
|
||||
gold_pay_type=douyu_config_value("gold_pay_type", config.gold_pay_type),
|
||||
gift_id=douyu_config_value("gift_id", config.gift_id),
|
||||
skin_id=douyu_config_value("skin_id", config.skin_id),
|
||||
@@ -170,6 +178,7 @@ def list_task_accounts(
|
||||
Account.nickname.ilike(pattern),
|
||||
Account.tag.ilike(pattern),
|
||||
Account.game_name.ilike(pattern),
|
||||
Account.esports_game_name.ilike(pattern),
|
||||
))
|
||||
rows = query.order_by(Account.id.desc()).limit(500).all()
|
||||
return [_account_out(account) for account in rows]
|
||||
|
||||
@@ -542,6 +542,9 @@ class DouyuConfigOut(BaseModel):
|
||||
legacy_act_alias: str = "cjm"
|
||||
room_id: str = "9263298"
|
||||
elite_amount: int = 3000
|
||||
esports_manual_id: str = "1W0yGkOdDbAXb"
|
||||
esports_act_alias: str = "20260226ZMGDG"
|
||||
esports_amount: int = 3000
|
||||
gold_pay_type: int = 1
|
||||
gift_id: str = "23643"
|
||||
skin_id: str = "2942"
|
||||
@@ -557,6 +560,9 @@ class DouyuConfigOut(BaseModel):
|
||||
"legacy_act_alias": self.legacy_act_alias,
|
||||
"room_id": self.room_id,
|
||||
"elite_amount": self.elite_amount,
|
||||
"esports_manual_id": self.esports_manual_id,
|
||||
"esports_act_alias": self.esports_act_alias,
|
||||
"esports_amount": self.esports_amount,
|
||||
"gold_pay_type": self.gold_pay_type,
|
||||
"gift_id": self.gift_id,
|
||||
"skin_id": self.skin_id,
|
||||
@@ -572,6 +578,9 @@ class DouyuConfigUpdate(BaseModel):
|
||||
legacy_act_alias: Optional[str] = None
|
||||
room_id: Optional[str] = None
|
||||
elite_amount: Optional[int] = Field(None, ge=1)
|
||||
esports_manual_id: Optional[str] = None
|
||||
esports_act_alias: Optional[str] = None
|
||||
esports_amount: Optional[int] = Field(None, ge=1)
|
||||
gold_pay_type: Optional[int] = Field(None, ge=1, le=9)
|
||||
gift_id: Optional[str] = None
|
||||
skin_id: Optional[str] = None
|
||||
@@ -657,6 +666,11 @@ class DouyuTaskAccountOut(BaseModel):
|
||||
exchange_balance: Optional[int] = None
|
||||
bind_status: str = ""
|
||||
change_role_wait_time: Optional[int] = None
|
||||
esports_points: Optional[int] = None
|
||||
esports_game_name: str = ""
|
||||
esports_game_channel: str = ""
|
||||
esports_bind_status: str = ""
|
||||
esports_change_role_wait_time: Optional[int] = None
|
||||
assigned_to: Optional[int] = None
|
||||
assigned_username: Optional[str] = None
|
||||
|
||||
|
||||
@@ -277,6 +277,53 @@ class DouyuBatchRunner:
|
||||
account.bind_status = status
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
|
||||
def _apply_esports_bind_info_to_account(self, account: Account, bind_info: dict, status: str) -> None:
|
||||
"""将电竞手册角色状态写入专属字段,避免覆盖精英宝典数据。"""
|
||||
role_name = str(bind_info.get("role_name") or "")
|
||||
account.esports_game_name = role_name or account.esports_game_name
|
||||
account.esports_game_channel = self._role_channel(bind_info) or account.esports_game_channel
|
||||
account.esports_change_role_wait_time = self._to_int(bind_info.get("change_role_wait_time"))
|
||||
account.esports_bind_status = status
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
|
||||
def _esports_bind_state(
|
||||
self,
|
||||
client: DouyuActivityClient,
|
||||
act_alias: str,
|
||||
) -> dict:
|
||||
"""查询电竞手册活动状态,接口同时返回当前角色和换绑冷却信息。"""
|
||||
activity_info = client.esports_bind_info(act_alias)
|
||||
activity_snapshot = self._bind_snapshot(activity_info)
|
||||
esports_bound = activity_snapshot["is_bound_act"]
|
||||
has_selected_role = bool(activity_snapshot["role_name"])
|
||||
tx_act = activity_info.get("tx_act") or {}
|
||||
return {
|
||||
**activity_snapshot,
|
||||
"is_bound_role": has_selected_role,
|
||||
"act_alias": act_alias,
|
||||
"game_id": tx_act.get("gameId") or "",
|
||||
"esports_bound": esports_bound,
|
||||
"has_selected_role": has_selected_role,
|
||||
"bind_ready_for_confirm": has_selected_role and not esports_bound,
|
||||
"bind_confirmed": esports_bound,
|
||||
"bind_phase": "confirmed" if esports_bound else ("role_ready" if has_selected_role else "waiting_role"),
|
||||
"activity_bind_info": activity_info,
|
||||
"activity_bind_snapshot": activity_snapshot,
|
||||
"role_source": "activity",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _esports_role_text(state: dict) -> str:
|
||||
role_name = str(state.get("role_name") or "")
|
||||
channel = " / ".join(
|
||||
str(part)
|
||||
for part in [state.get("plat_name"), state.get("area_name")]
|
||||
if part
|
||||
)
|
||||
if not role_name:
|
||||
return ""
|
||||
return f"{role_name}({channel})" if channel else role_name
|
||||
|
||||
def _mark_task(
|
||||
self,
|
||||
db: Session,
|
||||
@@ -415,6 +462,100 @@ class DouyuBatchRunner:
|
||||
result["points"] = last_points
|
||||
return False
|
||||
|
||||
def _refresh_esports_handbook(
|
||||
self,
|
||||
client: DouyuActivityClient,
|
||||
account: Account,
|
||||
*,
|
||||
manual_id: str,
|
||||
) -> dict:
|
||||
"""刷新电竞手册开通状态并将积分写回账号。"""
|
||||
result = client.esports_user_info(manual_id=manual_id)
|
||||
manual_type = self._to_int(result.get("manual_type"))
|
||||
manual_score = self._to_int(result.get("manual_score"))
|
||||
account.esports_points = manual_score
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
return {
|
||||
"esports_manual_type": manual_type,
|
||||
"esports_manual_score": manual_score,
|
||||
"esports_expire_time": result.get("expire_time"),
|
||||
"esports_user_info": result,
|
||||
"esports_points": manual_score,
|
||||
"points": manual_score,
|
||||
}
|
||||
|
||||
def _wait_esports_open_after_payment(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
client: DouyuActivityClient,
|
||||
*,
|
||||
manual_id: str,
|
||||
result: dict,
|
||||
baseline_manual_type: int | None,
|
||||
baseline_manual_score: int | None,
|
||||
) -> bool:
|
||||
"""等待电竞手册支付到账,以 manualType=1 或积分变化作为成功条件。"""
|
||||
deadline = time.monotonic() + DOUYU_PAYMENT_POLL_SECONDS
|
||||
result["payment_polling"] = True
|
||||
result["esports_manual_type_baseline"] = baseline_manual_type
|
||||
result["esports_manual_score_baseline"] = baseline_manual_score
|
||||
poll_count = 0
|
||||
last_manual_type = baseline_manual_type
|
||||
last_manual_score = baseline_manual_score
|
||||
|
||||
while not self._stop.is_set() and time.monotonic() <= deadline:
|
||||
try:
|
||||
handbook_result = self._refresh_esports_handbook(
|
||||
client,
|
||||
account,
|
||||
manual_id=manual_id,
|
||||
)
|
||||
db.commit()
|
||||
poll_count += 1
|
||||
last_manual_type = handbook_result["esports_manual_type"]
|
||||
last_manual_score = handbook_result["esports_manual_score"]
|
||||
result.update(handbook_result)
|
||||
result["payment_poll_count"] = poll_count
|
||||
result["payment_polling"] = True
|
||||
opened = (
|
||||
last_manual_type is not None
|
||||
and last_manual_type >= 1
|
||||
) or (
|
||||
baseline_manual_score is not None
|
||||
and last_manual_score is not None
|
||||
and last_manual_score > baseline_manual_score
|
||||
)
|
||||
if opened:
|
||||
result["payment_polling"] = False
|
||||
result["esports_opened"] = True
|
||||
return True
|
||||
self._update_task_progress(
|
||||
db,
|
||||
task,
|
||||
"running",
|
||||
"电竞手册支付码已生成,等待开通到账"
|
||||
f"(类型 {last_manual_type if last_manual_type is not None else '-'},"
|
||||
f"积分 {last_manual_score if last_manual_score is not None else '-'})",
|
||||
result,
|
||||
)
|
||||
except Exception as exc:
|
||||
poll_count += 1
|
||||
result["payment_poll_count"] = poll_count
|
||||
result["payment_poll_error"] = str(exc)
|
||||
self._update_task_progress(db, task, "running", f"等待电竞手册到账: {exc}", result)
|
||||
if self._stop.wait(DOUYU_PAYMENT_POLL_INTERVAL):
|
||||
break
|
||||
|
||||
result["payment_polling"] = False
|
||||
result["esports_opened"] = False
|
||||
result["esports_manual_type"] = last_manual_type
|
||||
result["esports_manual_score"] = last_manual_score
|
||||
result["esports_points"] = last_manual_score
|
||||
result["points"] = last_manual_score
|
||||
return False
|
||||
|
||||
def _wait_gold_balance_after_payment(
|
||||
self,
|
||||
db: Session,
|
||||
@@ -1093,6 +1234,257 @@ class DouyuBatchRunner:
|
||||
result,
|
||||
)
|
||||
|
||||
def _execute_prepare_esports_bind(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
cookie: str,
|
||||
config: dict,
|
||||
):
|
||||
"""打开电竞手册绑定面板:查活动状态、当前角色和换绑冷却。"""
|
||||
client = self._client(cookie)
|
||||
act_alias = str(config.get("esports_act_alias") or "").strip()
|
||||
if not act_alias:
|
||||
self._mark_task(db, task, "failed", "请先配置电竞手册活动 actAlias")
|
||||
return
|
||||
|
||||
state = self._esports_bind_state(client, act_alias)
|
||||
esports_bound = state["esports_bound"]
|
||||
role_text = self._esports_role_text(state)
|
||||
self._apply_esports_bind_info_to_account(
|
||||
account,
|
||||
state,
|
||||
"esports_bound" if esports_bound else ("esports_bind_ready" if role_text else "game_not_bound"),
|
||||
)
|
||||
# 二维码用于重新选择角色,不应因为已有角色或换绑冷却而隐藏。
|
||||
# 冷却是否允许最终由 actBind 返回结果决定。
|
||||
qr_result = client.get_esports_bind_qr(act_alias)
|
||||
result = {
|
||||
**state,
|
||||
**qr_result,
|
||||
"esports_bind_dialog": True,
|
||||
"can_open_role_selector": True,
|
||||
}
|
||||
if esports_bound:
|
||||
message = f"电竞手册已绑定: {role_text or '-'},可扫码换绑"
|
||||
elif role_text:
|
||||
message = f"当前角色: {role_text},可扫码切换角色或直接完成绑定"
|
||||
else:
|
||||
message = "请扫码选择游戏角色,完成后查询最新角色"
|
||||
self._mark_task(db, task, "success", message, result)
|
||||
|
||||
def _execute_get_esports_bind_qr(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
cookie: str,
|
||||
config: dict,
|
||||
):
|
||||
"""生成电竞手册切换角色用的腾讯入口。"""
|
||||
client = self._client(cookie)
|
||||
act_alias = str(config.get("esports_act_alias") or "").strip()
|
||||
if not act_alias:
|
||||
self._mark_task(db, task, "failed", "请先配置电竞手册活动 actAlias")
|
||||
return
|
||||
|
||||
state = self._esports_bind_state(client, act_alias)
|
||||
qr_result = client.get_esports_bind_qr(act_alias)
|
||||
result = {
|
||||
**state,
|
||||
**qr_result,
|
||||
"esports_bind_dialog": True,
|
||||
"can_open_role_selector": True,
|
||||
"bind_phase": "switching_role",
|
||||
}
|
||||
account.esports_bind_status = "esports_role_switching"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"success",
|
||||
"请在腾讯页面选择角色,返回后查询最新角色",
|
||||
result,
|
||||
)
|
||||
|
||||
def _execute_confirm_esports_bind(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
cookie: str,
|
||||
config: dict,
|
||||
):
|
||||
"""通过 actBind 确认电竞手册绑定,并回读唯一状态接口确认结果。"""
|
||||
client = self._client(cookie)
|
||||
act_alias = str(config.get("esports_act_alias") or "").strip()
|
||||
if not act_alias:
|
||||
self._mark_task(db, task, "failed", "请先配置电竞手册活动 actAlias")
|
||||
return
|
||||
|
||||
account.esports_bind_status = "esports_bind_confirming"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
self._update_task_progress(
|
||||
db,
|
||||
task,
|
||||
"running",
|
||||
"正在确认电竞手册绑定",
|
||||
{
|
||||
"bind_phase": "confirming",
|
||||
"bind_confirmed": False,
|
||||
},
|
||||
)
|
||||
confirm_result = client.confirm_esports_bind(
|
||||
act_alias,
|
||||
room_id=str(config.get("room_id") or "9263298"),
|
||||
)
|
||||
after_state = self._esports_bind_state(client, act_alias)
|
||||
result = {
|
||||
**after_state,
|
||||
"confirm": confirm_result,
|
||||
"bind_phase": "confirmed" if after_state["esports_bound"] else "confirm_failed",
|
||||
}
|
||||
if not after_state["esports_bound"]:
|
||||
self._apply_esports_bind_info_to_account(account, after_state, "esports_bind_ready")
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"failed",
|
||||
f"电竞手册绑定未生效: {self._esports_role_text(after_state) or '-'}",
|
||||
result,
|
||||
)
|
||||
return
|
||||
|
||||
self._apply_esports_bind_info_to_account(account, after_state, "esports_bound")
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"success",
|
||||
f"电竞手册绑定成功: {self._esports_role_text(after_state) or '-'}",
|
||||
result,
|
||||
)
|
||||
|
||||
def _execute_query_esports_game_name(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
cookie: str,
|
||||
config: dict,
|
||||
):
|
||||
"""查询电竞手册活动返回的最新角色和换绑冷却状态。"""
|
||||
client = self._client(cookie)
|
||||
act_alias = str(config.get("esports_act_alias") or "").strip()
|
||||
if not act_alias:
|
||||
self._mark_task(db, task, "failed", "请先配置电竞手册活动 actAlias")
|
||||
return
|
||||
|
||||
state = self._esports_bind_state(client, act_alias)
|
||||
role_name = state["role_name"]
|
||||
is_bound = state["esports_bound"]
|
||||
self._apply_esports_bind_info_to_account(
|
||||
account,
|
||||
state,
|
||||
"esports_bound" if is_bound else ("esports_bind_ready" if role_name else "game_not_bound"),
|
||||
)
|
||||
result = {
|
||||
**state,
|
||||
"esports_bind_dialog": True,
|
||||
"can_open_role_selector": True,
|
||||
}
|
||||
if role_name:
|
||||
message = f"最新角色: {self._esports_role_text(state)}"
|
||||
else:
|
||||
message = "未查询到游戏角色,请先切换角色"
|
||||
self._mark_task(db, task, "success", message, result)
|
||||
|
||||
def _execute_create_esports_qr(
|
||||
self,
|
||||
db: Session,
|
||||
task: DouyuTask,
|
||||
account: Account,
|
||||
cookie: str,
|
||||
config: dict,
|
||||
):
|
||||
"""生成电竞手册支付二维码,并通过活动状态确认开通到账。"""
|
||||
client = self._client(cookie)
|
||||
ctn = str(self._task_payload(task).get("ctn") or "")
|
||||
if not ctn:
|
||||
ctn = client.acf_ccn(refresh_subscribe=True)
|
||||
act_alias = str(config.get("esports_act_alias") or "").strip()
|
||||
manual_id = str(config.get("esports_manual_id") or "").strip()
|
||||
if not act_alias or not manual_id:
|
||||
self._mark_task(db, task, "failed", "请先配置电竞手册活动 actAlias 和 manualID")
|
||||
return
|
||||
|
||||
baseline_manual_type = None
|
||||
baseline_manual_score = None
|
||||
baseline_result: dict = {}
|
||||
try:
|
||||
baseline_result = self._refresh_esports_handbook(client, account, manual_id=manual_id)
|
||||
baseline_manual_type = baseline_result["esports_manual_type"]
|
||||
baseline_manual_score = baseline_result["esports_manual_score"]
|
||||
db.commit()
|
||||
except Exception as exc:
|
||||
self._push_log("warning", f"生成电竞手册支付码前查询活动状态失败: {exc}")
|
||||
|
||||
if baseline_manual_type is not None and baseline_manual_type >= 1:
|
||||
account.esports_bind_status = "esports_opened"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"success",
|
||||
f"电竞手册已开通,积分: {baseline_manual_score if baseline_manual_score is not None else '-'}",
|
||||
{**baseline_result, "esports_opened": True, "payment_polling": False},
|
||||
)
|
||||
return
|
||||
|
||||
result = client.create_esports_qr(
|
||||
ctn=ctn,
|
||||
act_alias=act_alias,
|
||||
amount=int(config["esports_amount"]),
|
||||
room_id=str(config["room_id"]),
|
||||
)
|
||||
result.update(baseline_result)
|
||||
account.esports_bind_status = "esports_qr_created"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
self._update_task_progress(db, task, "running", "电竞手册支付码已生成,等待开通到账", result)
|
||||
opened = self._wait_esports_open_after_payment(
|
||||
db,
|
||||
task,
|
||||
account,
|
||||
client,
|
||||
manual_id=manual_id,
|
||||
result=result,
|
||||
baseline_manual_type=baseline_manual_type,
|
||||
baseline_manual_score=baseline_manual_score,
|
||||
)
|
||||
if self._stop.is_set():
|
||||
self._mark_task(db, task, "stopped", "任务已停止", result)
|
||||
return
|
||||
if opened:
|
||||
account.esports_bind_status = "esports_opened"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"success",
|
||||
f"电竞手册已开通,积分: {account.esports_points if account.esports_points is not None else '-'}",
|
||||
result,
|
||||
)
|
||||
return
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"failed",
|
||||
"未检测到电竞手册开通到账"
|
||||
f",类型: {result.get('esports_manual_type', '-')},"
|
||||
f"积分: {result.get('esports_manual_score', '-')}",
|
||||
result,
|
||||
)
|
||||
|
||||
def _execute_create_gold_qr(self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict):
|
||||
payload = self._task_payload(task)
|
||||
amount = int(payload.get("amount") or payload.get("gold_amount") or 1)
|
||||
@@ -1474,6 +1866,11 @@ class DouyuBatchRunner:
|
||||
"get_bind_qr": self._execute_get_bind_qr,
|
||||
"confirm_bind": self._execute_confirm_bind,
|
||||
"create_elite_qr": self._execute_create_elite_qr,
|
||||
"prepare_esports_bind": self._execute_prepare_esports_bind,
|
||||
"get_esports_bind_qr": self._execute_get_esports_bind_qr,
|
||||
"query_esports_game_name": self._execute_query_esports_game_name,
|
||||
"confirm_esports_bind": self._execute_confirm_esports_bind,
|
||||
"create_esports_qr": self._execute_create_esports_qr,
|
||||
"create_gold_qr": self._execute_create_gold_qr,
|
||||
"donate_elite_gift": self._execute_donate_elite_gift,
|
||||
"query_points": self._execute_query_points,
|
||||
|
||||
@@ -17,6 +17,11 @@ SUPPORTED_DOUYU_TASK_TYPES = {
|
||||
"get_bind_qr": "获取绑定二维码",
|
||||
"confirm_bind": "确认绑定",
|
||||
"create_elite_qr": "开通精英宝典30",
|
||||
"prepare_esports_bind": "绑定电竞手册角色",
|
||||
"get_esports_bind_qr": "切换电竞角色",
|
||||
"query_esports_game_name": "查询最新游戏角色",
|
||||
"confirm_esports_bind": "确认电竞手册绑定",
|
||||
"create_esports_qr": "开通电竞手册30",
|
||||
"create_gold_qr": "充值鱼翅",
|
||||
"donate_elite_gift": "赠送精英令",
|
||||
"query_points": "一键查询积分",
|
||||
@@ -39,6 +44,9 @@ DOUYU_CONFIG_DEFAULTS = {
|
||||
"legacy_act_alias": "cjm",
|
||||
"room_id": "9263298",
|
||||
"elite_amount": 3000,
|
||||
"esports_manual_id": "1W0yGkOdDbAXb",
|
||||
"esports_act_alias": "20260226ZMGDG",
|
||||
"esports_amount": 3000,
|
||||
"gold_pay_type": 1,
|
||||
"gift_id": "23643",
|
||||
"skin_id": "2942",
|
||||
|
||||
Reference in New Issue
Block a user