This commit is contained in:
sansenhoshi
2026-01-04 17:15:40 +08:00
commit 275f05ee4a
207 changed files with 12305 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment
from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from .data_proc import *
from .img_generator import *
import io
import base64
__plugin_meta__ = PluginMetadata(
name="打卡记鹿",
description="你今天鹿管了ma?",
usage="at机器人 发送:打卡 "
"直接发送:查卡(查询打卡记录)",
type="application",
)
record = on_command("打卡记鹿", aliases={"打卡"}, rule=to_me())
query = on_command("查询记录", aliases={"查卡"})
@record.handle()
async def do_job(bot: Bot, ev: MessageEvent):
# 获取当前日期的年份和月份
now = datetime.now()
year = now.year
month = now.month
day = now.day
# 获取发信人信息
uid = str(ev.user_id)
message_id = ev.message_id
# 添加一条记录
await record_month(uid, day)
# 获取记录
img = await draw_calendar_grid_image(uid, year, month)
text_msg = MessageSegment.text("这是您的打卡记鹿:\n")
image_msg = MessageSegment.image(pic2b64(img))
mix_msg = (text_msg,)
mix_msg += image_msg
reply_msg = (MessageSegment.reply(message_id),)
reply_msg += mix_msg
await record.finish(reply_msg)
def pic2b64(pic: Image) -> str:
buf = io.BytesIO()
pic.save(buf, format='PNG')
base64_str = base64.b64encode(buf.getvalue()).decode()
return 'base64://' + base64_str
@query.handle()
async def query_job(bot: Bot, ev: MessageEvent):
# 获取当前日期的年份和月份
now = datetime.now()
year = now.year
month = now.month
# 获取发信人信息
uid = str(ev.user_id)
message_id = ev.message_id
# 获取记录
img_file = await draw_calendar_grid_image(uid, year, month)
text_msg = MessageSegment.text("这是您的记鹿:\n")
image_msg = MessageSegment.image(pic2b64(img_file))
mix_msg = (text_msg,)
mix_msg += image_msg
reply_msg = (MessageSegment.reply(message_id),)
reply_msg += mix_msg
await record.finish(reply_msg)
+48
View File
@@ -0,0 +1,48 @@
import os
import json
from datetime import datetime, timedelta
filepath = os.path.dirname(__file__).replace("\\", "/")
data_path = filepath+'/deer_pipe/'
# 记录信息
async def record_month(uid, day: int):
# 获取当前日期
current_date = datetime.now()
formatted_date = current_date.strftime('%Y-%m')
json_file_path = f"{data_path}/{formatted_date}.json"
if os.path.exists(json_file_path):
# 如果文件存在,则读取其中的数据
with open(json_file_path, 'r', encoding='utf-8') as file:
data = json.load(file)
if uid in data:
day_list = data[uid]
day_list.append(day)
else:
day_list = [day]
data[uid] = day_list
else:
# 如果文件不存在,则创建一个新的空数据结构
day_list = [day]
data = {'uid': day_list}
with open(json_file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
# 读取当月信息
async def get_records(uid):
day_list = []
# 获取当前日期
current_date = datetime.now()
formatted_date = current_date.strftime('%Y-%m')
json_file_path = f"{data_path}/{formatted_date}.json"
if os.path.exists(json_file_path):
# 如果文件存在,则读取其中的数据
with open(json_file_path, 'r', encoding='utf-8') as file:
data = json.load(file)
if uid in data:
day_list = data[uid]
else:
day_list = [0]
return day_list
@@ -0,0 +1,458 @@
{
"2931589710": [
1,
2,
3,
4,
4,
5,
16,
16
],
"437916206": [
1
],
"386911634": [
1,
2,
2,
3,
4,
6
],
"2083436520": [
1,
2,
3,
4,
5,
7,
8
],
"3201624634": [
1,
1,
2,
3,
4,
5,
6,
7,
8,
16
],
"1192582155": [
1,
2
],
"1640154565": [
1,
2,
3,
6
],
"2652920210": [
1,
1,
2,
3,
4,
5,
6,
7,
8
],
"1532106994": [
1,
1,
1,
2,
3,
4,
5,
6,
7,
8,
16
],
"1651620969": [
1,
1,
2,
3,
3,
4,
5,
6,
8
],
"2448320195": [
1,
1,
2,
3,
4,
4,
4,
4,
6,
7,
8
],
"2295029310": [
1
],
"2658100993": [
1,
4,
5
],
"2656360014": [
1
],
"736875294": [
1,
6,
7
],
"1827595836": [
1,
1
],
"198295337": [
1,
2,
3,
4,
5,
5,
6,
8,
8,
8,
8,
8
],
"3098632978": [
1,
2,
2,
3,
4,
5,
6,
7
],
"2815144875": [
1,
1,
2,
2,
2,
3,
3,
4,
5,
5,
6,
6,
7,
8,
16,
16
],
"906575749": [
1
],
"237957101": [
1,
2,
3,
5,
6,
6
],
"1564571378": [
1
],
"870520151": [
1,
5
],
"1357024971": [
1
],
"2872682608": [
1,
2,
2,
2,
3,
4,
5,
6,
6,
7,
8
],
"1327093900": [
1,
2
],
"3698818486": [
1
],
"1766551374": [
1,
2,
3,
4,
5,
6,
7,
8
],
"1207799328": [
1,
1,
5
],
"2111373772": [
1,
2,
2,
6
],
"2193159167": [
1
],
"249266185": [
1,
2,
5,
6
],
"2857915028": [
1,
2,
2,
2,
2
],
"1251742023": [
1,
2,
3,
4,
5,
6,
7,
7,
8
],
"1327784910": [
1,
2,
3
],
"499867291": [
1,
5,
6,
6
],
"2640981487": [
2,
3
],
"1198453273": [
2,
3
],
"2635940476": [
2,
2,
2
],
"2603150110": [
2,
2,
3,
4,
4,
5,
7,
7,
8,
16
],
"2094292259": [
2
],
"736676100": [
2
],
"1584905882": [
2,
4,
5
],
"2996805685": [
2,
4,
6
],
"827398256": [
2,
2,
2,
5,
6,
7,
7
],
"1102997238": [
2,
4,
5,
7,
8
],
"1722173847": [
2,
2
],
"1041319467": [
2
],
"962608623": [
2
],
"948186339": [
2,
5,
6
],
"276336778": [
2,
3,
4,
5,
6,
6,
16
],
"2388483507": [
2
],
"3256631053": [
2,
3,
4,
5,
6,
8
],
"156098539": [
2
],
"1533703664": [
2
],
"1097829523": [
2
],
"724041940": [
2,
3,
5,
6,
8,
16
],
"381268035": [
2
],
"2374035622": [
2,
3,
5,
6
],
"2781719263": [
2
],
"2449768430": [
3
],
"1870323135": [
3
],
"2591212935": [
3
],
"1545789605": [
4,
6
],
"1136531059": [
5,
6,
7
],
"2830599695": [
5
],
"1119162975": [
5,
8
],
"1458143947": [
6,
6,
7
],
"2478314183": [
6
],
"3092179918": [
6
],
"1628420979": [
6,
7
],
"1952839455": [
6,
7
],
"2174309103": [
6
],
"410300249": [
6
],
"1611414080": [
6
],
"1187039544": [
6,
7,
7,
8
],
"1745882130": [
7,
16,
16
],
"2321247175": [
7
],
"2530894749": [
7
],
"986239980": [
8
]
}
@@ -0,0 +1,69 @@
{
"uid": [
27
],
"1532106994": [
27,
28,
29,
30
],
"978975474": [
27
],
"1990345380": [
27,
28,
28,
31
],
"1521198648": [
27,
28,
29,
30,
31
],
"919617516": [
27
],
"603055627": [
27
],
"2982067505": [
27
],
"3201624634": [
28,
29,
30
],
"2652920210": [
28,
30
],
"598111936": [
28
],
"2815144875": [
28
],
"1611414080": [
28
],
"2908237931": [
28
],
"2752597456": [
28
],
"237957101": [
28
],
"3529206922": [
29
],
"2366805964": [
30
]
}
@@ -0,0 +1,94 @@
{
"uid": [
1
],
"1990345380": [
1
],
"1532106994": [
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
18,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30
],
"1521198648": [
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
18,
19,
20,
21,
22,
23,
24,
25,
26,
28,
29,
30
],
"2931589710": [
4,
13,
13,
18
],
"1187039544": [
5
],
"919617516": [
6,
7,
13,
26
],
"2366805964": [
7
],
"1196293185": [
13
],
"2908237931": [
18
],
"3070520589": [
23
],
"1520107082": [
25
]
}
@@ -0,0 +1,63 @@
{
"uid": [
1
],
"2652920210": [
1
],
"1532106994": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
11,
12,
13,
14,
15,
16,
16,
17,
18,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
],
"1521198648": [
1,
3,
8,
10
],
"2813477297": [
1
],
"361060689": [
1
],
"2603150110": [
9
],
"2931589710": [
9,
10
],
"1187039544": [
13
]
}
@@ -0,0 +1,39 @@
{
"uid": [
1
],
"1532106994": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
26,
26,
28,
29,
30
],
"2603150110": [
6
]
}
@@ -0,0 +1,51 @@
{
"uid": [
1
],
"1532106994": [
1,
2,
3,
3,
4,
5,
5,
7,
8,
9,
10,
11,
12,
13,
14,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
25,
26,
28,
29,
30,
31
],
"2083436520": [
1
],
"2931589710": [
1
],
"2783677365": [
3,
4,
7
]
}
@@ -0,0 +1,41 @@
{
"uid": [
2
],
"1532106994": [
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
22,
23,
24,
25
],
"2603150110": [
3
],
"249266185": [
19
],
"1136531059": [
25
]
}
@@ -0,0 +1,70 @@
{
"uid": [
6
],
"1532106994": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
24,
25,
26,
27,
28
],
"2815144875": [
24
],
"2931589710": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24
],
"2872682608": [
24
],
"1205646769": [
24
],
"2635940476": [
24
],
"1120308711": [
24
]
}
@@ -0,0 +1,39 @@
{
"uid": [
1
],
"1532106994": [
1,
3,
5
],
"2449768430": [
1
],
"962608623": [
1
],
"2931589710": [
12,
25
],
"1171418826": [
12
],
"1205646769": [
12,
31
],
"2815144875": [
12,
25,
27,
31
],
"547868332": [
12
],
"2872682608": [
12
]
}
@@ -0,0 +1,47 @@
{
"uid": [
1
],
"1171418826": [
1,
2,
10,
15,
17
],
"2931589710": [
1,
14
],
"1640154565": [
1
],
"2815144875": [
2,
3,
6
],
"1916766091": [
10,
16
],
"3301750": [
14,
15,
16,
17,
18,
28
],
"3451383113": [
14
],
"2683512785": [
15
],
"947571000": [
17,
19,
24
]
}
@@ -0,0 +1,5 @@
{
"uid": [
7
]
}
@@ -0,0 +1,5 @@
{
"uid": [
5
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

+118
View File
@@ -0,0 +1,118 @@
import calendar
from datetime import datetime, timedelta
from PIL import Image, ImageDraw, ImageFont, ImageOps
from .data_proc import *
import random
filepath = os.path.dirname(__file__).replace("\\", "/")
async def draw_calendar_grid_image(uid, year, month):
# 获取该月的第一天是星期几,以及这个月有多少天
first_weekday, num_days = calendar.monthrange(year, month)
# 调整第一天的索引,使周日对应0,周六对应6
first_weekday = (first_weekday + 1) % 7
# 设置单元格尺寸和内边距
cell_size = 50
cell_padding = 5
# 计算当前月份的行数
num_rows = (num_days + first_weekday + 6) // 7 + 1 # +1 行用于留空
# 计算图片宽度和高度
image_width = 7 * (cell_size + cell_padding) - cell_padding
image_height = num_rows * (cell_size + cell_padding) - cell_padding
# 创建图像对象
img = Image.new("RGBA", (image_width, image_height), "white")
draw = ImageDraw.Draw(img)
font_path = filepath + "/font/SourceHanSansCN-Medium.otf"
print(font_path)
font_normal = ImageFont.truetype(font=font_path, size=18)
font_large = ImageFont.truetype(font=font_path, size=24)
# 绘制网格线
for i in range(7):
x = i * (cell_size + cell_padding)
draw.line([(x, 55), (x, image_height)], fill="black", width=1)
for j in range(0, image_height + cell_size, cell_size + cell_padding):
draw.line([(0, j), (image_width, j)], fill="black", width=1)
# 小🦌
deer_pipe_path = filepath + "/img/deer_pipe/deer_pipe.jpg"
deer_pipe_img = Image.open(deer_pipe_path)
deer_pipe_img = deer_pipe_img.resize((54, 50))
# 画标题
title = f"{month}月打卡记鹿"
text_length = draw.textlength(text=title, font=font_large)
img_xy = (int(((image_width - text_length + 55) / 2) - 55), 5)
title_pos = ((image_width - text_length + 55) / 2, 10)
img.paste(deer_pipe_img, img_xy)
draw.text(title_pos, title, fill="black", font=font_large)
# 获取🦌信息
days = await get_records(uid)
# 填充日期
date = datetime(year, month, 1)
for day in range(1, num_days + 1):
weekday = (first_weekday + day - 1) % 7
row = (first_weekday + day - 1) // 7 + 1 # +1 行用于留空
x = weekday * (cell_size + cell_padding) + cell_padding
y = row * (cell_size + cell_padding) + cell_padding
img.paste(deer_pipe_img, (x - 4, y))
draw.text((x+20, y - 2), f"{str(day)}", fill="black", font=font_normal)
if day in days:
im = get_random_right()
img = image_paste(im, img, (x - 4, y))
# 保存图片
# img.save(output_image_path)
# 显示图片
# img.show()
img = ImageOps.expand(img, border=5, fill="black")
img = ImageOps.expand(img, border=5, fill="white")
return img
# 全局变量,用于存储已经选择过的文件名
selected_images = []
def get_random_right():
global selected_images
path = filepath + "/img/deer_pipe/right"
# 过滤掉已经选择过的文件名
im_name = [name for name in os.listdir(path) if name not in selected_images]
# 如果所有文件都已经选择过,重新初始化已选择列表
if not im_name:
selected_images = []
im_name = os.listdir(path)
index = random.randint(0, len(im_name) - 1)
im = im_name[index]
selected_images.append(im) # 将选择的文件名添加到已选择列表中
im_path = os.path.join(path, im)
im_file = Image.open(im_path)
im_file = im_file.resize((50, 50))
return im_file
# 图片粘贴
def image_paste(paste_image, under_image, pos):
"""
:param paste_image: 需要粘贴的图片
:param under_image: 底图
:param pos: 位置(x,y)坐标
:return: 返回图片
"""
# 获取需要贴入图片的透明通道
r, g, b, alpha = paste_image.split()
# 粘贴时将alpha值传递至mask属性
under_image.paste(paste_image, pos, alpha)
return under_image