"""斗鱼任务执行器:送礼(由 douyu_runner.py 按功能域拆分)。""" from __future__ import annotations from datetime import datetime, timezone from sqlalchemy.orm import Session from core.douyu import DouyuActivityClient from ..models import Account, DouyuTask DOUYU_GIFT_POINTS_REFRESH_TIMES = 3 DOUYU_GIFT_POINTS_REFRESH_INTERVAL = 2 class DonateMixin: """送礼域:精英令/电竞任务礼物赠送与积分确认。""" def _refresh_points_after_elite_gift( self, db: Session, task: DouyuTask, account: Account, client: DouyuActivityClient, cookie: str, ctn: str | None, result: dict, baseline_points: int | None, gift_count: int, ) -> dict: """赠送精英令后短轮询积分;1 个精英令约等于 10 积分。""" expected_gain = max(0, gift_count) * 10 target_points = baseline_points + expected_gain if baseline_points is not None else None result["gift_points_baseline"] = baseline_points result["gift_points_expected_gain"] = expected_gain result["gift_points_target"] = target_points last_points = None refresh_result: dict = {} for index in range(1, DOUYU_GIFT_POINTS_REFRESH_TIMES + 1): refresh_result = self._refresh_account_points(client, account, cookie, ctn=ctn) db.commit() last_points = refresh_result["points"] result.update(refresh_result) result["gift_points_refresh_count"] = index if target_points is None or (last_points is not None and last_points >= target_points): result["gift_points_confirmed"] = target_points is None or last_points is not None return refresh_result if index < DOUYU_GIFT_POINTS_REFRESH_TIMES: self._update_task_progress( db, task, "running", f"赠送精英令成功,等待积分同步(当前 {last_points if last_points is not None else '-'},预期 {target_points})", result, ) if self._stop.wait(DOUYU_GIFT_POINTS_REFRESH_INTERVAL): break result["gift_points_confirmed"] = False result["points"] = last_points return refresh_result def _execute_donate_esports_gift( self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict, *, gift_name: str, config_gift_id_key: str, config_skin_id_key: str, ): """赠送电竞手册任务礼物并刷新独立积分。""" payload = self._task_payload(task) try: gift_count = max(1, int(payload.get("gift_count") or payload.get("count") or 1)) except (TypeError, ValueError): self._mark_task(db, task, "failed", "赠送数量必须是正整数") return manual_id = str(config.get("esports_manual_id") or "").strip() gift_id = str(payload.get("gift_id") or config.get(config_gift_id_key) or "").strip() skin_id = str(payload.get("skin_id") or config.get(config_skin_id_key) or "").strip() room_id = str(payload.get("room_id") or config.get("room_id") or "").strip() if not manual_id or not gift_id or not skin_id or not room_id: self._mark_task(db, task, "failed", "请先完整配置电竞手册、房间和礼物参数") return client = self._client(cookie) baseline_points = account.esports_points try: baseline = self._refresh_esports_handbook(client, account, manual_id=manual_id) baseline_points = baseline["esports_points"] db.commit() except Exception as exc: self._push_log("warning", f"赠送{gift_name}前刷新电竞积分失败: {exc}") result = client.donate_esports_gift( gift_name=gift_name, gift_count=gift_count, room_id=room_id, gift_id=gift_id, skin_id=skin_id, ) result.update( { "gift_name": gift_name, "gift_id": gift_id, "skin_id": skin_id, "gift_count": gift_count, "esports_points_baseline": baseline_points, } ) refresh_errors = [] try: result.update(self._refresh_account_gold_balance(client, account)) except Exception as exc: refresh_errors.append(f"鱼翅余额: {exc}") try: points_result = self._refresh_esports_handbook(client, account, manual_id=manual_id) result.update(points_result) result["esports_points_after_gift"] = points_result["esports_points"] result["esports_points_changed"] = ( baseline_points is not None and points_result["esports_points"] is not None and points_result["esports_points"] != baseline_points ) except Exception as exc: refresh_errors.append(f"电竞积分: {exc}") if refresh_errors: result["refresh_errors"] = refresh_errors account.esports_bind_status = "esports_gift_donated" account.updated_at = datetime.now(timezone.utc) message = f"赠送{gift_name}成功: {gift_count}" if account.gold_balance is not None: message += f",鱼翅余额: {account.gold_balance}" if account.esports_points is not None: message += f",电竞积分: {account.esports_points}" self._mark_task(db, task, "success", message, result) def _execute_donate_esports_chicken_gift( self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict, ): """赠送冠军鸡腿。""" self._execute_donate_esports_gift( db, task, account, cookie, config, gift_name="冠军鸡腿", config_gift_id_key="esports_chicken_gift_id", config_skin_id_key="esports_chicken_skin_id", ) def _execute_donate_esports_firework_gift( self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict, ): """赠送冠军烟花。""" self._execute_donate_esports_gift( db, task, account, cookie, config, gift_name="冠军烟花", config_gift_id_key="esports_firework_gift_id", config_skin_id_key="esports_firework_skin_id", ) def _execute_donate_elite_gift(self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict): payload = self._task_payload(task) gift_count = int(payload.get("gift_count") or payload.get("count") or 1) client = self._client(cookie) ctn = None baseline_points = account.points try: ctn = client.acf_ccn(refresh_subscribe=False) baseline_result = self._refresh_account_points(client, account, cookie, ctn=ctn) db.commit() baseline_points = baseline_result["points"] except Exception as exc: self._push_log("warning", f"赠送精英令前刷新积分失败: {exc}") result = client.donate_elite_gift( gift_count=gift_count, room_id=str(payload.get("room_id") or config["room_id"]), gift_id=str(payload.get("gift_id") or config["gift_id"]), skin_id=str(payload.get("skin_id") or config["skin_id"]), ) result["gift_points_baseline"] = baseline_points refresh_errors = [] try: result.update(self._refresh_account_gold_balance(client, account)) except Exception as exc: refresh_errors.append(f"鱼翅余额: {exc}") try: result.update( self._refresh_points_after_elite_gift( db, task, account, client, cookie, ctn, result, baseline_points, gift_count, ) ) except Exception as exc: refresh_errors.append(f"积分: {exc}") if refresh_errors: result["refresh_errors"] = refresh_errors account.bind_status = "gift_donated" account.updated_at = datetime.now(timezone.utc) message = f"赠送精英令成功: {gift_count}" if account.gold_balance is not None: message += f",鱼翅余额: {account.gold_balance}" if account.points is not None: message += f",积分: {account.points}" if result.get("gift_points_target") is not None and not result.get("gift_points_confirmed"): message += f"(未确认涨到 {result['gift_points_target']})" self._mark_task(db, task, "success", message, result)