mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-Nonebot.git
synced 2026-04-01 22:04:51 +00:00
feat(cf): 新增查询CodeForces Rating功能,快来实践你的队友吧👁👁
This commit is contained in:
parent
722be73e14
commit
f30312fd6b
6 changed files with 140 additions and 6 deletions
|
|
@ -41,3 +41,7 @@ typing_extensions
|
|||
psutil
|
||||
Beautifulsoup4
|
||||
aiohttp
|
||||
pydantic
|
||||
matplotlib
|
||||
httpx
|
||||
crypto
|
||||
34
src/clover_sqlite/models/codeforces.py
Normal file
34
src/clover_sqlite/models/codeforces.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from tortoise import fields
|
||||
from src.clover_sqlite.data_init.db_connect import Model
|
||||
|
||||
class CodeForces(Model):
|
||||
cf_id = fields.CharField(max_length=128, null=True, discription="用户codeforces账号")
|
||||
user_id = fields.CharField(max_length=64, discription="用户openid")
|
||||
|
||||
class Meta:
|
||||
table = "codeforces"
|
||||
table_description = "cf表"
|
||||
|
||||
|
||||
@classmethod
|
||||
async def get_cf_id(cls, user_id: str | None):
|
||||
cf_table = await CodeForces.filter(user_id=user_id).first()
|
||||
if cf_table:
|
||||
return cf_table.cf_id
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@classmethod
|
||||
async def insert_cf_id(cls, cf_id: str | None, user_id: str | None):
|
||||
if not cf_id:
|
||||
return -1
|
||||
|
||||
cf_table = await CodeForces.filter(user_id=user_id).first()
|
||||
if cf_table:
|
||||
cf_table.cf_id = cf_id
|
||||
await cf_table.save()
|
||||
return 1
|
||||
else:
|
||||
await cls.create(cf_id=cf_id, user_id=user_id)
|
||||
return 0
|
||||
|
|
@ -53,3 +53,9 @@ wenku8_password = "<passwd>"
|
|||
多米HTTP代理api
|
||||
"""
|
||||
proxy_api = "<KEY>"
|
||||
|
||||
"""
|
||||
CodeForces API
|
||||
"""
|
||||
codeforces_key = "<KEY>"
|
||||
codeforces_secret = "<KEY>"
|
||||
|
|
@ -10,6 +10,9 @@ os.makedirs(image_local_qq_image_path, exist_ok=True)
|
|||
# 个人图片路径
|
||||
image_local_path= path+"/image/MaoYuNa"
|
||||
os.makedirs(image_local_path, exist_ok=True)
|
||||
# cf ratings路径
|
||||
rating_path = path+'/image/cf_ratings'
|
||||
os.makedirs(rating_path, exist_ok=True)
|
||||
# 塔罗牌图片路径
|
||||
tarots_img_path = path+'/image/tarot/TarotImages/'
|
||||
os.makedirs(tarots_img_path, exist_ok=True)
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ from src.clover_sqlite.models.user import UserList
|
|||
|
||||
menu = ["/重启","/今日运势","/今日塔罗","/图","/随机图","/搜番","/日报","/点歌","/摸摸头","/群老婆","/今日老婆", "/开启ai","/关闭ai","/角色列表","/添加人设", "/更新人设", "/删除人设", "/切换人设", "/管理员注册",
|
||||
"/待办", "/test","/天气","我喜欢你", "❤", "/待办查询", "/新建待办", "/删除待办" ,"/cf","/B站搜索", "/BV搜索", "/喜报", "/悲报", "/luxun","/鲁迅说",
|
||||
"/奶龙", "/repo", "/info", "/menu", "/轻小说","/本季新番","/下季新番","/新番观察","/绝对色感" ,"/jm"]
|
||||
"/奶龙", "/repo", "/info", "/menu", "/轻小说","/本季新番","/下季新番","/新番观察","/绝对色感" ,"/jm", "/cfrt"]
|
||||
|
||||
send_menu = ["/menu","/今日运势","/今日塔罗","/图","/随机图","搜番","/日报","/点歌","/摸摸头","/群老婆","/待办","/天气",
|
||||
"/待办查询", "/新建待办", "/删除待办" ,"/cf","/B站搜索", "/BV搜索", "/喜报", "/悲报","/鲁迅说",
|
||||
"/轻小说","/本季新番","/新番观察","/下季新番","/绝对色感","/jm"]
|
||||
"/轻小说","/本季新番","/新番观察","/下季新番","/绝对色感","https://codeforces.com/api/user.rating?handle=/jm"]
|
||||
|
||||
async def check_value_in_menu(message: MessageEvent) -> bool:
|
||||
value = message.get_plaintext().strip().split(" ")
|
||||
|
|
@ -30,7 +30,7 @@ async def check_value_in_menu(message: MessageEvent) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
check = on_message(rule=to_me() & Rule(check_value_in_menu), priority=10)
|
||||
check = on_message(rule=to_me() & Rule(check_value_in_menu), priority=1)
|
||||
@check.handle()
|
||||
async def handle_function(message: MessageEvent):
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ from nonebot.plugin import on_command
|
|||
from nonebot.rule import to_me
|
||||
from nonebot.adapters.qq import Message, MessageEvent, MessageSegment
|
||||
from pathlib import Path
|
||||
from src.configs.path_config import path
|
||||
|
||||
from src.clover_sqlite.models.codeforces import CodeForces
|
||||
from src.configs.path_config import path, rating_path
|
||||
from src.clover_sqlite.models.user import UserList
|
||||
from datetime import datetime
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
cf_query = on_command("cf", rule=to_me(), priority=10, block=True)
|
||||
@cf_query.handle()
|
||||
|
|
@ -34,6 +39,88 @@ async def get_cf_rounds():
|
|||
await cf_query.finish(msg)
|
||||
|
||||
|
||||
cf_ratings = on_command("cfrt", rule=to_me(), priority=10, block=True)
|
||||
@cf_ratings.handle()
|
||||
async def get_cf_ratings(message: MessageEvent):
|
||||
content = message.get_plaintext().strip().split(" ")
|
||||
if len(content) > 1:
|
||||
status = await CodeForces.insert_cf_id(content[1], message.get_user_id())
|
||||
if status == 1:
|
||||
await cf_ratings.send(f"成功将cf账号换绑为{content[1]}🥳")
|
||||
elif status == 0:
|
||||
await cf_ratings.send(f"成功绑定cf账号{content[1]}🎉")
|
||||
else:
|
||||
await cf_ratings.finish(f"出现未知错误,我也不知道啥原因,但是能触发这个没什么用的异常也挺厉害的。")
|
||||
|
||||
cf_id = await CodeForces.get_cf_id(message.author.id)
|
||||
if cf_id:
|
||||
await cf_ratings.send("正在查询CodeForces Rating,请稍后👀")
|
||||
try:
|
||||
results = requests.get("https://codeforces.com/api/user.rating?handle={}".format(cf_id)).json()
|
||||
except BaseException:
|
||||
await cf_ratings.finish("API请求失败,这绝对不是咱的错,绝对不是!")
|
||||
|
||||
if results["status"] != "OK":
|
||||
await cf_ratings.finish(f"未查询到该用户的信息哦,请检查用户名{cf_id}是否正确💦\n可使用 /cfrt+用户名 换绑")
|
||||
|
||||
# 准备绘图数据
|
||||
timestamps = []
|
||||
ratings = []
|
||||
# 遍历所有比赛记录
|
||||
for result in results["result"]:
|
||||
# 提取时间戳和rating数据
|
||||
timestamps.append(result["ratingUpdateTimeSeconds"])
|
||||
ratings.append(result["newRating"])
|
||||
|
||||
if not timestamps:
|
||||
await cf_ratings.finish("未找到Rating变化记录哦~")
|
||||
|
||||
# 转换时间戳为日期格式
|
||||
dates = [datetime.fromtimestamp(ts) for ts in timestamps]
|
||||
|
||||
# 创建图表
|
||||
plt.figure(figsize=(12, 6))
|
||||
plt.plot(
|
||||
dates,
|
||||
ratings,
|
||||
marker='o',
|
||||
linestyle='-',
|
||||
color='#2196F3',
|
||||
linewidth=2,
|
||||
markersize=6,
|
||||
label='CF Rating'
|
||||
)
|
||||
|
||||
# 美化图表
|
||||
plt.title(f'Codeforces Rating Trend ({cf_id})', fontsize=14)
|
||||
plt.xlabel('Contest Time', fontsize=12)
|
||||
plt.ylabel('Rating', fontsize=12)
|
||||
plt.grid(True, linestyle='--', alpha=0.7)
|
||||
|
||||
# 自动旋转日期标签
|
||||
plt.gcf().autofmt_xdate()
|
||||
|
||||
# 添加最新分数标注
|
||||
last_rating = ratings[-1]
|
||||
plt.annotate(f'{last_rating}',
|
||||
xy=(dates[-1], last_rating),
|
||||
xytext=(10, -20),
|
||||
textcoords='offset points',
|
||||
arrowprops=dict(arrowstyle="->"))
|
||||
|
||||
# 保存图片
|
||||
save_path = rating_path + f'cf_rating_{cf_id}.png'
|
||||
plt.savefig(save_path, bbox_inches='tight', dpi=300)
|
||||
plt.close() # 释放内存
|
||||
|
||||
# 发送图片(根据你的机器人框架调整发送逻辑)
|
||||
await cf_ratings.finish(MessageSegment.file_image(Path(save_path)))
|
||||
|
||||
else:
|
||||
await cf_ratings.send("您还未绑定CodeForces账户\n请输入 /cfrt+账户名 来绑定吧。")
|
||||
|
||||
|
||||
|
||||
def get_match_phase(phase):
|
||||
phase_map = {
|
||||
"BEFORE": "未开始",
|
||||
|
|
|
|||
Loading…
Reference in a new issue