新增斗鱼活动任务模块:绑定、宝典、鱼翅、积分、兑换等功能

- 新增 activity_client.py:封装斗鱼活动/兑换/充值/送礼接口
- 新增 cookie_utils.py:Cookie 解析与规范化工具
- 新增 douyu_service/douyu_runner:斗鱼任务服务层与批量执行器
- 新增 douyu 路由:任务类型查询、账号列表、配置管理、商品管理、批量任务、WebSocket 日志
- 新增 models/schemas:DouyuTask/DouyuConfig/DouyuGoodsSnapshot 模型,Account 扩展点数/鱼翅/绑定状态等字段
- 新增数据库迁移:斗鱼活动相关表与 accounts 字段补充
- 新增前端 DouyuTasksPage 任务操作台页面
- 兑换商品请求添加 sec-ch-ua 反检测头
- 兑换商品支持最多 8 次重试 + csrf_token 自动刷新
- 注册 douyu:task / douyu:config 权限点
- 侧边栏新增斗鱼分组与任务操作台菜单入口
This commit is contained in:
yml2213
2026-07-24 16:11:39 +08:00
parent f91c05c108
commit 62099e8d68
17 changed files with 2506 additions and 1 deletions
+128
View File
@@ -514,6 +514,134 @@ class HuyaRechargeGoodsOut(BaseModel):
}
# ---- 斗鱼活动任务 ----
class DouyuConfigOut(BaseModel):
manual_id: str = "G4KA4Qnz4LDp7"
rid: str = "9263298"
bind_act_alias: str = "20250213NQCYX"
confirm_act_alias: str = "20260120QYOOB"
legacy_act_alias: str = "cjm"
room_id: str = "9263298"
elite_amount: int = 3000
gold_pay_type: int = 1
gift_id: str = "23643"
skin_id: str = "2942"
updated_at: Optional[datetime] = None
@model_serializer
def _serialize(self) -> dict[str, Any]:
return {
"manual_id": self.manual_id,
"rid": self.rid,
"bind_act_alias": self.bind_act_alias,
"confirm_act_alias": self.confirm_act_alias,
"legacy_act_alias": self.legacy_act_alias,
"room_id": self.room_id,
"elite_amount": self.elite_amount,
"gold_pay_type": self.gold_pay_type,
"gift_id": self.gift_id,
"skin_id": self.skin_id,
"updated_at": _ensure_tz(self.updated_at).isoformat() if self.updated_at else None,
}
class DouyuConfigUpdate(BaseModel):
manual_id: Optional[str] = None
rid: Optional[str] = None
bind_act_alias: Optional[str] = None
confirm_act_alias: Optional[str] = None
legacy_act_alias: Optional[str] = None
room_id: Optional[str] = None
elite_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
class DouyuTaskBatchRequest(BaseModel):
account_ids: list[int]
task_type: str
concurrency: int = Field(3, ge=1, le=10)
payload: dict[str, Any] = Field(default_factory=dict)
class DouyuTaskOut(BaseModel):
id: int
batch_id: str
account_id: int
account_username: str = ""
account_uid: str = ""
account_nickname: str = ""
task_type: str
status: str
message: str = ""
result: Optional[dict[str, Any]] = None
created_by: int
created_at: Optional[datetime] = None
finished_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
@model_serializer
def _serialize(self) -> dict[str, Any]:
return {
"id": self.id,
"batch_id": self.batch_id,
"account_id": self.account_id,
"account_username": self.account_username,
"account_uid": self.account_uid,
"account_nickname": self.account_nickname,
"task_type": self.task_type,
"status": self.status,
"message": self.message,
"result": self.result,
"created_by": self.created_by,
"created_at": _ensure_tz(self.created_at).isoformat() if self.created_at else None,
"finished_at": _ensure_tz(self.finished_at).isoformat() if self.finished_at else None,
}
class DouyuGoodsOut(BaseModel):
id: int
commodity_id: str
name: str = ""
score: Optional[int] = None
status: str = ""
raw: Optional[dict[str, Any]] = None
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
@model_serializer
def _serialize(self) -> dict[str, Any]:
return {
"id": self.id,
"commodity_id": self.commodity_id,
"name": self.name,
"score": self.score,
"status": self.status,
"raw": self.raw,
"updated_at": _ensure_tz(self.updated_at).isoformat() if self.updated_at else None,
}
class DouyuTaskAccountOut(BaseModel):
id: int
username: str
uid: str = ""
nickname: str = ""
tag: str = ""
points: Optional[int] = None
game_name: str = ""
game_channel: str = ""
gold_balance: Optional[int] = None
exchange_balance: Optional[int] = None
bind_status: str = ""
change_role_wait_time: Optional[int] = None
assigned_to: Optional[int] = None
assigned_username: Optional[str] = None
# ---- 代理配置 ----
class ProxyConfigOut(BaseModel):
enabled: bool = False