Files
abot/plugins/epic_free/main.py
liuwei bb73d07809 重构:新增定时插件业务逻辑内聚到各自插件目录
- daily_news 插件内置百度新闻与60s图片获取逻辑,移除对 base.func_news 的业务依赖\n- epic_free 插件内置周五判断与免费游戏抓取逻辑,移除对 base.func_epic 的业务依赖\n- daily_ranking 插件内置排行生成与积分奖励逻辑,不再依赖 MessageStorage 业务封装\n- sehuatang_push 改为引用插件目录内的抓取与PDF生成实现,将核心业务代码迁入插件目录\n- 确保新插件可独立承载自身业务逻辑,平台层仅提供调度与基础设施能力
2026-04-16 16:16:07 +08:00

187 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
import requests
from bs4 import BeautifulSoup
from base.plugin_common.message_plugin_interface import MessagePluginInterface
from base.plugin_common.plugin_interface import PluginStatus
from utils.robot_cmd.robot_command import GroupBotManager
class EpicFreePlugin(MessagePluginInterface):
"""Epic 免费游戏自动播报插件。"""
FEATURE_KEY = "EPIC"
FEATURE_DESCRIPTION = "📊 EPIC自动播报 [每周五自动发送]"
@property
def name(self) -> str:
return "Epic播报"
@property
def version(self) -> str:
return "1.0.0"
@property
def description(self) -> str:
return "将 Epic 免费游戏播报从系统任务迁移到插件任务。"
@property
def author(self) -> str:
return "ABOT Team"
@property
def commands(self) -> List[str]:
return []
@property
def feature_key(self) -> Optional[str]:
return self.FEATURE_KEY
@property
def feature_description(self) -> Optional[str]:
return self.FEATURE_DESCRIPTION
def __init__(self):
super().__init__()
self.feature = self.register_feature()
def initialize(self, context: Dict[str, Any]) -> bool:
return True
def start(self) -> bool:
self.status = PluginStatus.RUNNING
return True
def stop(self) -> bool:
self.status = PluginStatus.STOPPED
return True
def can_process(self, message: Dict[str, Any]) -> bool:
return False
async def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
return False, None
def get_schedule_actions(self) -> List[Dict[str, Any]]:
return [
{
"action_key": "weekly_free_games_push",
"name": "Epic免费游戏推送",
"description": "每周五推送 Epic 当周免费游戏",
"trigger_type": "every_weekday_time",
"trigger_config": {"weekday": 4, "time_str": "10:00"},
"target_scope": "all_enabled_groups",
"target_config": {},
"payload": {"force": False},
"default_enabled": True,
}
]
async def run_scheduled_action(self, action_key: str, context: Dict[str, Any]) -> Dict[str, Any]:
if action_key != "weekly_free_games_push":
return {
"success": False,
"summary": f"不支持的动作: {action_key}",
"detail": {"action_key": action_key},
}
if not self.bot:
return {"success": False, "summary": "bot 未注入", "detail": {}}
payload = context.get("payload") or {}
force = bool(payload.get("force", False))
if not force and not self._is_friday():
# 非周五时默认跳过;手动触发可通过 payload.force 强制执行。
return {"success": True, "summary": "今天不是周五,已跳过 Epic 播报", "detail": {"skipped": True}}
target_groups = [str(g).strip() for g in (context.get("target_groups") or []) if str(g).strip()]
if not target_groups:
target_groups = [
gid for gid in GroupBotManager.get_group_list()
if GroupBotManager.get_group_permission(gid, self.feature).value == "enabled"
]
if not target_groups:
return {"success": False, "summary": "没有可推送目标群", "detail": {"target_count": 0}}
try:
text = self._get_free_games()
except Exception as e:
return {"success": False, "summary": f"获取 Epic 免费游戏失败: {e}", "detail": {"error": str(e)}}
success_groups = []
failed_groups = {}
for gid in target_groups:
try:
await self.bot.send_text_message(gid, text)
success_groups.append(gid)
except Exception as e:
failed_groups[gid] = str(e)
return {
"success": len(failed_groups) == 0,
"summary": f"Epic播报完成: 成功{len(success_groups)}群, 失败{len(failed_groups)}",
"detail": {
"target_count": len(target_groups),
"success_groups": success_groups,
"failed_groups": failed_groups,
"force": force,
},
}
@staticmethod
def _is_friday() -> bool:
"""判断是否周五(插件内实现)。"""
return datetime.today().weekday() == 4
@staticmethod
def _get_free_games() -> str:
"""抓取 Epic 免费游戏列表(插件内实现)。"""
url = "https://steamstats.cn/xi"
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36 Edg/90.0.818.41"
)
}
resp = requests.get(url, headers=headers, timeout=20)
resp.raise_for_status()
resp.encoding = resp.apparent_encoding
soup = BeautifulSoup(resp.text, "html.parser")
text = "今日喜加一 :https://store.epicgames.com/en-US/free-games\n"
tbody = soup.find("tbody")
if not tbody:
return text + "未抓取到免费游戏列表"
rows = tbody.find_all("tr")
idx = 1
for row in rows:
cols = row.find_all("td")
if len(cols) < 7:
continue
name = (cols[1].string or "").strip()
gametype = (cols[2].string or "").replace(" ", "").strip()
start = (cols[3].string or "").replace(" ", "").strip()
end = (cols[4].string or "").replace(" ", "").strip()
permanent = (cols[5].string or "").replace(" ", "").strip()
origin_span = cols[6].find("span")
origin = (origin_span.string or "").replace(" ", "").strip() if origin_span else ""
href_value = ""
for a in cols[6].find_all("a"):
href_value = a.get("href", "") or href_value
text += (
f"序号:{idx}\n"
f"游戏名称:{name}\n"
f"DLC/game{gametype}\n"
f"开始时间:{start}\n"
f"结束时间:{end}\n"
f"是否永久:{permanent}\n"
f"平台:{origin}\n"
f"URL{href_value}\n"
)
idx += 1
return text