移动 poster 模块到 common
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-03-09 14:40:27 +08:00
parent 72e21cd9aa
commit 392c699b33
10 changed files with 145 additions and 95 deletions

View File

@ -0,0 +1,11 @@
"""
Subscribe 模块,用于向一些订阅的频道广播消息
"""
from .service import broadcast as broadcast
from .service import dep_poster_service as dep_poster_service
from .service import DepPosterService as DepPosterService
from .service import PosterService as PosterService
from .subscribe_info import PosterInfo as PosterInfo
from .subscribe_info import POSTER_INFO_DATA as POSTER_INFO_DATA
from .subscribe_info import register_poster_info as register_poster_info

View File

@ -6,7 +6,8 @@ from pydantic import BaseModel, ValidationError
from konabot.common.longtask import LongTaskTarget from konabot.common.longtask import LongTaskTarget
from konabot.common.pager import PagerQuery, PagerResult from konabot.common.pager import PagerQuery, PagerResult
from konabot.common.path import DATA_PATH from konabot.common.path import DATA_PATH
from konabot.plugins.poster.repository import IPosterRepo
from .repository import IPosterRepo
class ChannelData(BaseModel): class ChannelData(BaseModel):
@ -18,9 +19,9 @@ class PosterData(BaseModel):
def is_the_same_target(target1: LongTaskTarget, target2: LongTaskTarget) -> bool: def is_the_same_target(target1: LongTaskTarget, target2: LongTaskTarget) -> bool:
if (target1.is_private_chat and not target2.is_private_chat): if target1.is_private_chat and not target2.is_private_chat:
return False return False
if (target2.is_private_chat and not target1.is_private_chat): if target2.is_private_chat and not target1.is_private_chat:
return False return False
if target1.platform != target2.platform: if target1.platform != target2.platform:
return False return False
@ -58,7 +59,9 @@ class LocalPosterRepo(IPosterRepo):
len1 = len(self.data.channels[channel].targets) len1 = len(self.data.channels[channel].targets)
return len0 != len1 return len0 != len1
async def get_subscribed_channels(self, target: LongTaskTarget, pager: PagerQuery) -> PagerResult[str]: async def get_subscribed_channels(
self, target: LongTaskTarget, pager: PagerQuery
) -> PagerResult[str]:
channels: list[str] = [] channels: list[str] = []
for channel_id, channel in self.data.channels.items(): for channel_id, channel in self.data.channels.items():
for t in channel.targets: for t in channel.targets:
@ -95,7 +98,9 @@ async def local_poster_data():
data = PosterData() data = PosterData()
else: else:
try: try:
data = PosterData.model_validate_json(LOCAL_POSTER_DATA_PATH.read_text()) data = PosterData.model_validate_json(
LOCAL_POSTER_DATA_PATH.read_text()
)
except ValidationError: except ValidationError:
data = PosterData() data = PosterData()
yield data yield data
@ -109,4 +114,3 @@ async def local_poster():
DepLocalPosterRepo = Annotated[LocalPosterRepo, Depends(local_poster)] DepLocalPosterRepo = Annotated[LocalPosterRepo, Depends(local_poster)]

View File

@ -4,9 +4,10 @@ from nonebot.params import Depends
from nonebot_plugin_alconna import UniMessage from nonebot_plugin_alconna import UniMessage
from konabot.common.longtask import LongTaskTarget from konabot.common.longtask import LongTaskTarget
from konabot.common.pager import PagerQuery, PagerResult from konabot.common.pager import PagerQuery, PagerResult
from konabot.plugins.poster.poster_info import POSTER_INFO_DATA
from konabot.plugins.poster.repo_local_data import local_poster from .subscribe_info import POSTER_INFO_DATA
from konabot.plugins.poster.repository import IPosterRepo from .repo_local_data import local_poster
from .repository import IPosterRepo
class PosterService: class PosterService:
@ -27,7 +28,9 @@ class PosterService:
channel = self.parse_channel_id(channel) channel = self.parse_channel_id(channel)
return await self.repo.remove_channel_target(channel, target) return await self.repo.remove_channel_target(channel, target)
async def broadcast(self, channel: str, message: UniMessage[Any] | str) -> list[LongTaskTarget]: async def broadcast(
self, channel: str, message: UniMessage[Any] | str
) -> list[LongTaskTarget]:
channel = self.parse_channel_id(channel) channel = self.parse_channel_id(channel)
targets = await self.repo.get_channel_targets(channel) targets = await self.repo.get_channel_targets(channel)
for target in targets: for target in targets:
@ -35,7 +38,9 @@ class PosterService:
await target.send_message(message, at=False) await target.send_message(message, at=False)
return targets return targets
async def get_channels(self, target: LongTaskTarget, pager: PagerQuery) -> PagerResult[str]: async def get_channels(
self, target: LongTaskTarget, pager: PagerQuery
) -> PagerResult[str]:
return await self.repo.get_subscribed_channels(target, pager) return await self.repo.get_subscribed_channels(target, pager)
async def fix_data(self): async def fix_data(self):
@ -56,4 +61,3 @@ async def broadcast(channel: str, message: UniMessage[Any] | str):
DepPosterService = Annotated[PosterService, Depends(dep_poster_service)] DepPosterService = Annotated[PosterService, Depends(dep_poster_service)]

View File

@ -4,7 +4,7 @@ from dataclasses import dataclass, field
@dataclass @dataclass
class PosterInfo: class PosterInfo:
aliases: set[str] = field(default_factory=set) aliases: set[str] = field(default_factory=set)
description: str = field(default='') description: str = field(default="")
POSTER_INFO_DATA: dict[str, PosterInfo] = {} POSTER_INFO_DATA: dict[str, PosterInfo] = {}
@ -12,4 +12,3 @@ POSTER_INFO_DATA: dict[str, PosterInfo] = {}
def register_poster_info(channel: str, info: PosterInfo): def register_poster_info(channel: str, info: PosterInfo):
POSTER_INFO_DATA[channel] = info POSTER_INFO_DATA[channel] = info

View File

@ -6,29 +6,34 @@ from loguru import logger
from nonebot import on_message from nonebot import on_message
import nonebot import nonebot
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot_plugin_alconna import (Alconna, Args, UniMessage, UniMsg, from nonebot_plugin_alconna import Alconna, Args, UniMessage, UniMsg, on_alconna
on_alconna)
from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_apscheduler import scheduler
from konabot.common import username from konabot.common import username
from konabot.common.longtask import DepLongTaskTarget from konabot.common.longtask import DepLongTaskTarget
from konabot.common.pager import PagerQuery from konabot.common.pager import PagerQuery
from konabot.plugins.kona_ph.core.message import (get_daily_report, from konabot.plugins.kona_ph.core.message import (
get_daily_report_v2, get_daily_report,
get_puzzle_description, get_daily_report_v2,
get_submission_message) get_puzzle_description,
get_submission_message,
)
from konabot.plugins.kona_ph.core.storage import get_today_date from konabot.plugins.kona_ph.core.storage import get_today_date
from konabot.plugins.kona_ph.manager import (PUZZLE_PAGE_SIZE, from konabot.plugins.kona_ph.manager import (
create_admin_commands, PUZZLE_PAGE_SIZE,
puzzle_manager) create_admin_commands,
from konabot.plugins.poster.poster_info import PosterInfo, register_poster_info puzzle_manager,
from konabot.plugins.poster.service import broadcast )
from konabot.common.subscribe import PosterInfo, register_poster_info, broadcast
create_admin_commands() create_admin_commands()
register_poster_info("每日谜题", info=PosterInfo( register_poster_info(
aliases={"konaph", "kona_ph", "KonaPH", "此方谜题", "KONAPH"}, "每日谜题",
description="此方 BOT 每日谜题推送", info=PosterInfo(
)) aliases={"konaph", "kona_ph", "KonaPH", "此方谜题", "KONAPH"},
description="此方 BOT 每日谜题推送",
),
)
cmd_submit = on_message(rule=to_me()) cmd_submit = on_message(rule=to_me())
@ -44,16 +49,22 @@ async def _(msg: UniMsg, target: DepLongTaskTarget):
if isinstance(result, str): if isinstance(result, str):
await target.send_message(result) await target.send_message(result)
else: else:
await target.send_message(get_submission_message( await target.send_message(
daily_puzzle_info=result.info, get_submission_message(
submission=result.submission, daily_puzzle_info=result.info,
puzzle=result.puzzle, submission=result.submission,
)) puzzle=result.puzzle,
)
)
cmd_query = on_alconna(Alconna( cmd_query = on_alconna(
r"re:(?:((?:(?:所以|话)说?)?今天的题目是什么[啊呀哇呢]?(?:\?)?)|今日谜?题目?)" Alconna(
), rule=to_me()) r"re:(?:((?:(?:所以|话)说?)?今天的题目是什么[啊呀哇呢]?(?:\?)?)|今日谜?题目?)"
),
rule=to_me(),
)
@cmd_query.handle() @cmd_query.handle()
async def _(target: DepLongTaskTarget): async def _(target: DepLongTaskTarget):
@ -64,9 +75,8 @@ async def _(target: DepLongTaskTarget):
await target.send_message(get_puzzle_description(p)) await target.send_message(get_puzzle_description(p))
cmd_query_submission = on_alconna(Alconna( cmd_query_submission = on_alconna(Alconna("今日答题情况"), rule=to_me())
"今日答题情况"
), rule=to_me())
@cmd_query_submission.handle() @cmd_query_submission.handle()
async def _(target: DepLongTaskTarget): async def _(target: DepLongTaskTarget):
@ -77,11 +87,15 @@ async def _(target: DepLongTaskTarget):
await target.send_message(get_daily_report_v2(manager, gid)) await target.send_message(get_daily_report_v2(manager, gid))
cmd_history = on_alconna(Alconna( cmd_history = on_alconna(
"re:历史(题目|谜题)", Alconna(
Args["page?", int], "re:历史(题目|谜题)",
Args["index_id?", str], Args["page?", int],
), rule=to_me()) Args["index_id?", str],
),
rule=to_me(),
)
@cmd_history.handle() @cmd_history.handle()
async def _(target: DepLongTaskTarget, index_id: str = "", page: int = 1): async def _(target: DepLongTaskTarget, index_id: str = "", page: int = 1):
@ -105,10 +119,10 @@ async def _(target: DepLongTaskTarget, index_id: str = "", page: int = 1):
puzzles = sorted(puzzles, key=lambda u: u[1], reverse=True) puzzles = sorted(puzzles, key=lambda u: u[1], reverse=True)
count_pages = ceil(len(puzzles) / PUZZLE_PAGE_SIZE) count_pages = ceil(len(puzzles) / PUZZLE_PAGE_SIZE)
if page <= 0 or page > count_pages: if page <= 0 or page > count_pages:
return await target.send_message(UniMessage.text( return await target.send_message(
f"页数只有 1 ~ {count_pages} 啦!" UniMessage.text(f"页数只有 1 ~ {count_pages} 啦!")
)) )
puzzles = puzzles[(page - 1) * PUZZLE_PAGE_SIZE: page * PUZZLE_PAGE_SIZE] puzzles = puzzles[(page - 1) * PUZZLE_PAGE_SIZE : page * PUZZLE_PAGE_SIZE]
for p, d in puzzles: for p, d in puzzles:
info = manager.daily_puzzle[manager.daily_puzzle_of_date[d]] info = manager.daily_puzzle[manager.daily_puzzle_of_date[d]]
msg = msg.text( msg = msg.text(
@ -120,22 +134,26 @@ async def _(target: DepLongTaskTarget, index_id: str = "", page: int = 1):
await target.send_message(msg) await target.send_message(msg)
cmd_leadboard = on_alconna(Alconna( cmd_leadboard = on_alconna(
"re:此方(解谜|谜题)排行榜", Alconna(
Args["page?", int], "re:此方(解谜|谜题)排行榜",
)) Args["page?", int],
)
)
@cmd_leadboard.handle() @cmd_leadboard.handle()
async def _(target: DepLongTaskTarget, page: int = 1): async def _(target: DepLongTaskTarget, page: int = 1):
async with puzzle_manager() as manager: async with puzzle_manager() as manager:
result = manager.get_leadboard(PagerQuery(page, 10)) result = manager.get_leadboard(PagerQuery(page, 10))
await target.send_message(result.to_unimessage( await target.send_message(
title="此方解谜排行榜", result.to_unimessage(
formatter=lambda data: ( title="此方解谜排行榜",
f"{data[1]} 已完成 | " formatter=lambda data: (
f"{username.get_username(data[0])}" f"{data[1]} 已完成 | {username.get_username(data[0])}"
),
) )
)) )
@scheduler.scheduled_job("cron", hour="8") @scheduler.scheduled_job("cron", hour="8")
@ -155,4 +173,3 @@ async def _():
driver = nonebot.get_driver() driver = nonebot.get_driver()

View File

@ -33,7 +33,7 @@ from konabot.plugins.kona_ph.core.storage import (
get_today_date, get_today_date,
puzzle_manager, puzzle_manager,
) )
from konabot.plugins.poster.service import broadcast from konabot.common.subscribe import broadcast
PUZZLE_PAGE_SIZE = 10 PUZZLE_PAGE_SIZE = 10

View File

@ -3,14 +3,15 @@ from nonebot_plugin_alconna import Alconna, Args, on_alconna
from konabot.common.longtask import DepLongTaskTarget from konabot.common.longtask import DepLongTaskTarget
from konabot.common.pager import PagerQuery from konabot.common.pager import PagerQuery
from konabot.plugins.poster.poster_info import POSTER_INFO_DATA from konabot.common.subscribe import POSTER_INFO_DATA, dep_poster_service
from konabot.plugins.poster.service import dep_poster_service
cmd_subscribe = on_alconna(Alconna( cmd_subscribe = on_alconna(
"订阅", Alconna(
Args["channel", str], "订阅",
)) Args["channel", str],
)
)
@cmd_subscribe.handle() @cmd_subscribe.handle()
@ -23,10 +24,12 @@ async def _(target: DepLongTaskTarget, channel: str):
await target.send_message(f"已经订阅过「{channel}」了") await target.send_message(f"已经订阅过「{channel}」了")
cmd_list = on_alconna(Alconna( cmd_list = on_alconna(
"re:(?:查询|我的|获取)订阅(列表)?", Alconna(
Args["page?", int], "re:(?:查询|我的|获取)订阅(列表)?",
)) Args["page?", int],
)
)
def better_channel_message(channel_id: str) -> str: def better_channel_message(channel_id: str) -> str:
@ -39,17 +42,24 @@ def better_channel_message(channel_id: str) -> str:
@cmd_list.handle() @cmd_list.handle()
async def _(target: DepLongTaskTarget, page: int = 1): async def _(target: DepLongTaskTarget, page: int = 1):
async with dep_poster_service() as service: async with dep_poster_service() as service:
result = await service.get_channels(target, PagerQuery( result = await service.get_channels(
page_index=page, target,
page_size=10, PagerQuery(
)) page_index=page,
await target.send_message(result.to_unimessage(title="订阅列表", formatter=better_channel_message)) page_size=10,
),
)
await target.send_message(
result.to_unimessage(title="订阅列表", formatter=better_channel_message)
)
cmd_list_available = on_alconna(Alconna( cmd_list_available = on_alconna(
"re:(查询)?可用订阅(列表)?", Alconna(
Args["page?", int], "re:(查询)?可用订阅(列表)?",
)) Args["page?", int],
)
)
@cmd_list_available.handle() @cmd_list_available.handle()
@ -58,13 +68,17 @@ async def _(target: DepLongTaskTarget, page: int = 1):
page_index=page, page_index=page,
page_size=10, page_size=10,
).apply(sorted(POSTER_INFO_DATA.keys())) ).apply(sorted(POSTER_INFO_DATA.keys()))
await target.send_message(result.to_unimessage(title="可用订阅列表", formatter=better_channel_message)) await target.send_message(
result.to_unimessage(title="可用订阅列表", formatter=better_channel_message)
)
cmd_unsubscribe = on_alconna(Alconna( cmd_unsubscribe = on_alconna(
"取消订阅", Alconna(
Args["channel", str], "取消订阅",
)) Args["channel", str],
)
)
@cmd_unsubscribe.handle() @cmd_unsubscribe.handle()
@ -79,6 +93,7 @@ async def _(target: DepLongTaskTarget, channel: str):
driver = nonebot.get_driver() driver = nonebot.get_driver()
@driver.on_startup @driver.on_startup
async def _(): async def _():
async with dep_poster_service() as service: async with dep_poster_service() as service:

View File

@ -4,8 +4,7 @@ from nonebot.internal.adapter.event import Event
from nonebot_plugin_alconna import UniMessage from nonebot_plugin_alconna import UniMessage
from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_apscheduler import scheduler
from konabot.plugins.poster.poster_info import PosterInfo, register_poster_info from konabot.common.subscribe import PosterInfo, register_poster_info, broadcast
from konabot.plugins.poster.service import broadcast
register_poster_info( register_poster_info(
"二十四节气", "二十四节气",
@ -98,4 +97,3 @@ async def _(event: Event):
msg = UniMessage.text(f"现在的节气是{date.term}") msg = UniMessage.text(f"现在的节气是{date.term}")
await msg.send(event) await msg.send(event)

View File

@ -1,20 +1,23 @@
import asyncio import asyncio
from nonebot import get_driver from nonebot import get_driver
from nonebot_plugin_alconna import UniMessage from nonebot_plugin_alconna import UniMessage
from konabot.plugins.poster.poster_info import register_poster_info, PosterInfo from konabot.common.subscribe import register_poster_info, PosterInfo, broadcast
from konabot.plugins.poster.service import broadcast
CHANNEL_STARTUP = "启动通知" CHANNEL_STARTUP = "启动通知"
register_poster_info(CHANNEL_STARTUP, PosterInfo( register_poster_info(
aliases=set(), CHANNEL_STARTUP,
description="当 Bot 重启时告知", PosterInfo(
)) aliases=set(),
description="当 Bot 重启时告知",
),
)
driver = get_driver() driver = get_driver()
@driver.on_startup @driver.on_startup
async def _(): async def _():
# 要尽量保证接受讯息的服务存在 # 要尽量保证接受讯息的服务存在
@ -30,4 +33,3 @@ async def _():
await broadcast(CHANNEL_STARTUP, UniMessage.text("此方 BOT 重启好了")) await broadcast(CHANNEL_STARTUP, UniMessage.text("此方 BOT 重启好了"))
asyncio.create_task(task()) asyncio.create_task(task())