From 9a5066cae8023d882e79de5e1181b2a9ecfed645 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 30 Aug 2026 20:00:09 +0800 Subject: [PATCH] =?UTF-8?q?type:=20=E6=94=B6=E7=AA=84=E6=96=97=E9=B1=BC?= =?UTF-8?q?=E6=89=8B=E5=86=8C=E4=B8=8E=E9=80=81=E7=A4=BC=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=99=A8=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/backend/services/douyu_runner_donate.py | 78 +++++++++++++++--- web/backend/services/douyu_runner_manual.py | 90 ++++++++++++++++----- 2 files changed, 137 insertions(+), 31 deletions(-) diff --git a/web/backend/services/douyu_runner_donate.py b/web/backend/services/douyu_runner_donate.py index 198f030..69cf9bb 100644 --- a/web/backend/services/douyu_runner_donate.py +++ b/web/backend/services/douyu_runner_donate.py @@ -2,16 +2,45 @@ from __future__ import annotations from datetime import datetime, timezone +from typing import Any, TYPE_CHECKING from sqlalchemy.orm import Session from core.douyu import DouyuActivityClient from ..models import Account, DouyuTask +if TYPE_CHECKING: + from .douyu_runner import DouyuBatchRunner + DOUYU_GIFT_POINTS_REFRESH_TIMES = 3 DOUYU_GIFT_POINTS_REFRESH_INTERVAL = 2 + class DonateMixin: """送礼域:精英令/电竞任务礼物赠送与积分确认。""" + + if TYPE_CHECKING: + _stop: Any + + def _client(self, cookie: str) -> DouyuActivityClient: ... + def _task_payload(self, task: DouyuTask) -> dict: ... + def _push_log(self, level: str, message: str) -> None: ... + def _mark_task(self, *args: Any, **kwargs: Any) -> None: ... + def _update_task_progress(self, *args: Any, **kwargs: Any) -> None: ... + def _refresh_account_points( + self, + client: DouyuActivityClient, + account: Account, + cookie: str, + *, + ctn: str | None = None, + ) -> dict: ... + def _refresh_account_gold_balance( + self, client: DouyuActivityClient, account: Account + ) -> dict: ... + def _refresh_esports_handbook( + self, client: DouyuActivityClient, account: Account, *, manual_id: str + ) -> dict: ... + def _refresh_points_after_elite_gift( self, db: Session, @@ -26,7 +55,9 @@ class DonateMixin: ) -> dict: """赠送精英令后短轮询积分;1 个精英令约等于 10 积分。""" expected_gain = max(0, gift_count) * 10 - target_points = baseline_points + expected_gain if baseline_points is not None else None + 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 @@ -34,13 +65,19 @@ class DonateMixin: 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) + 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 + 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( @@ -72,14 +109,20 @@ class DonateMixin: """赠送电竞手册任务礼物并刷新独立积分。""" payload = self._task_payload(task) try: - gift_count = max(1, int(payload.get("gift_count") or payload.get("count") or 1)) + 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() + 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", "请先完整配置电竞手册、房间和礼物参数") @@ -88,7 +131,9 @@ class DonateMixin: client = self._client(cookie) baseline_points = account.esports_points try: - baseline = self._refresh_esports_handbook(client, account, manual_id=manual_id) + baseline = self._refresh_esports_handbook( + client, account, manual_id=manual_id + ) baseline_points = baseline["esports_points"] db.commit() except Exception as exc: @@ -116,7 +161,9 @@ class DonateMixin: except Exception as exc: refresh_errors.append(f"鱼翅余额: {exc}") try: - points_result = self._refresh_esports_handbook(client, account, manual_id=manual_id) + 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"] = ( @@ -178,7 +225,9 @@ class DonateMixin: config_skin_id_key="esports_firework_skin_id", ) - def _execute_donate_elite_gift(self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict): + 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) @@ -186,7 +235,9 @@ class DonateMixin: baseline_points = account.points try: ctn = client.acf_ccn(refresh_subscribe=False) - baseline_result = self._refresh_account_points(client, account, cookie, ctn=ctn) + baseline_result = self._refresh_account_points( + client, account, cookie, ctn=ctn + ) db.commit() baseline_points = baseline_result["points"] except Exception as exc: @@ -228,7 +279,8 @@ class DonateMixin: 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"): + 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) - diff --git a/web/backend/services/douyu_runner_manual.py b/web/backend/services/douyu_runner_manual.py index 24eab64..665765a 100644 --- a/web/backend/services/douyu_runner_manual.py +++ b/web/backend/services/douyu_runner_manual.py @@ -3,6 +3,7 @@ from __future__ import annotations import time from datetime import datetime, timezone +from typing import Any, TYPE_CHECKING from sqlalchemy.orm import Session from core.douyu import DouyuActivityClient, DouyuActivityError @@ -10,8 +11,31 @@ from ..models import Account, DouyuTask from .douyu_service import account_uid, update_account_profile_from_cookie from .douyu_runner_core import DOUYU_PAYMENT_POLL_INTERVAL, DOUYU_PAYMENT_POLL_SECONDS +if TYPE_CHECKING: + from .douyu_runner import DouyuBatchRunner + + class ManualMixin: """手册域:精英/电竞手册开通支付、积分查询与到账轮询。""" + + if TYPE_CHECKING: + _stop: Any + + @staticmethod + def _to_int(value: Any) -> int | None: ... + + def _client(self, cookie: str) -> DouyuActivityClient: ... + def _task_payload(self, task: DouyuTask) -> dict: ... + def _push_log(self, level: str, message: str) -> None: ... + def _mark_task(self, *args: Any, **kwargs: Any) -> None: ... + def _update_task_progress(self, *args: Any, **kwargs: Any) -> None: ... + + @classmethod + def _confirm_act_alias(cls, config: dict) -> str: ... + + @classmethod + def _bind_qr_act_alias(cls, config: dict) -> str: ... + def _refresh_account_points( self, client: DouyuActivityClient, @@ -51,7 +75,9 @@ class ManualMixin: last_points = None while not self._stop.is_set() and time.monotonic() <= deadline: try: - points_result = self._refresh_account_points(client, account, cookie, ctn=ctn) + points_result = self._refresh_account_points( + client, account, cookie, ctn=ctn + ) db.commit() poll_count += 1 last_points = points_result["points"] @@ -73,7 +99,9 @@ class ManualMixin: 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) + self._update_task_progress( + db, task, "running", f"等待开通到账: {exc}", result + ) if self._stop.wait(DOUYU_PAYMENT_POLL_INTERVAL): break result["payment_polling"] = False @@ -138,10 +166,7 @@ class ManualMixin: 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 ( + 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 @@ -163,7 +188,9 @@ class ManualMixin: 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) + self._update_task_progress( + db, task, "running", f"等待电竞手册到账: {exc}", result + ) if self._stop.wait(DOUYU_PAYMENT_POLL_INTERVAL): break @@ -175,7 +202,9 @@ class ManualMixin: result["points"] = last_manual_score return False - def _execute_create_elite_qr(self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict): + def _execute_create_elite_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: @@ -192,15 +221,21 @@ class ManualMixin: ) account.bind_status = "elite_qr_created" account.updated_at = datetime.now(timezone.utc) - self._update_task_progress(db, task, "running", "精英宝典支付码已生成,等待开通到账", result) - opened = self._wait_points_after_payment(db, task, account, client, cookie, ctn, result) + self._update_task_progress( + db, task, "running", "精英宝典支付码已生成,等待开通到账", result + ) + opened = self._wait_points_after_payment( + db, task, account, client, cookie, ctn, result + ) if self._stop.is_set(): self._mark_task(db, task, "stopped", "任务已停止", result) return if opened: account.bind_status = "elite_opened" account.updated_at = datetime.now(timezone.utc) - self._mark_task(db, task, "success", f"精英宝典已开通,积分: {account.points}", result) + self._mark_task( + db, task, "success", f"精英宝典已开通,积分: {account.points}", result + ) return self._mark_task( db, @@ -226,14 +261,18 @@ class ManualMixin: 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") + 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_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() @@ -261,7 +300,9 @@ class ManualMixin: 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) + self._update_task_progress( + db, task, "running", "电竞手册支付码已生成,等待开通到账", result + ) opened = self._wait_esports_open_after_payment( db, task, @@ -314,14 +355,27 @@ class ManualMixin: account.esports_bind_status = "esports_points_queried" account.updated_at = datetime.now(timezone.utc) points = result["esports_points"] - self._mark_task(db, task, "success", f"电竞积分: {points if points is not None else '-'}", result) + self._mark_task( + db, + task, + "success", + f"电竞积分: {points if points is not None else '-'}", + result, + ) - def _execute_query_points(self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict): + def _execute_query_points( + self, db: Session, task: DouyuTask, account: Account, cookie: str, config: dict + ): client = self._client(cookie) ctn = client.acf_ccn(refresh_subscribe=False) result = self._refresh_account_points(client, account, cookie, ctn=ctn) account.bind_status = "points_queried" account.updated_at = datetime.now(timezone.utc) points = result["points"] - self._mark_task(db, task, "success", f"积分: {points if points is not None else '-'}", result) - + self._mark_task( + db, + task, + "success", + f"积分: {points if points is not None else '-'}", + result, + )