Merge pull request #65 from nicklly/nonebot2

更换原神日历风格
This commit is contained in:
惜月 2022-06-21 20:44:18 +08:00 committed by GitHub
commit 3144dc8e09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 466 additions and 63 deletions

View File

@ -1,5 +1,5 @@
from nonebot import require, get_bot, on_command, logger
from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot.adapters.onebot.v11 import MessageEvent, Message, MessageSegment
from nonebot.params import CommandArg
from nonebot.plugin import PluginMetadata
@ -26,7 +26,7 @@ __plugin_meta__ = PluginMetadata(
},
)
calendar = on_command('原神日历', aliases={"原神日历", 'ysrl', '原神日程'}, priority=24, block=True)
calendar = on_command('原神日历', aliases={"原神日历", '原神日程', 'ysrl', 'ysrc'}, priority=24, block=True)
calendar.__paimon_help__ = {
"usage": "原神日历",
"introduce": "查看原神活动日历后加on时间/off可以开启定时推送",
@ -48,7 +48,7 @@ async def send_calendar(push_id, push_data):
for server in push_data['server_list']:
im = await generate_day_schedule(server)
data['message'] = MessageBuild.Image(im)
data['message'] = MessageSegment.image(im)
await get_bot().call_api(api, **data)
logger.info(f'{push_data["type"]}{push_id}的原神日历推送成功')
except Exception as e:
@ -79,7 +79,7 @@ async def _(event: MessageEvent, msg: Message = CommandArg()):
if not msg:
im = await generate_day_schedule(server)
await calendar.finish(MessageBuild.Image(im))
await calendar.finish( MessageSegment.image(im))
else:
push_data = load_json('calender_push.json')
if msg.startswith(('开启', 'on', '打开')):

View File

@ -1,3 +1,4 @@
import os
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from utils.aiorequests import get
@ -6,8 +7,10 @@ import math
import functools
import re
# type 0 普通常驻任务深渊 1 新闻 2 蛋池 3 限时活动H5
res = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'template')
# type 0 普通常驻任务深渊 1 新闻 2 蛋池 3 限时活动H5
event_data = {
'cn': [],
}
@ -22,10 +25,15 @@ lock = {
ignored_key_words = [
"修复",
"版本内容专题页",
"内容专题页",
"米游社",
"调研",
"防沉迷"
"防沉迷",
"问卷",
"公平运营",
"纪行",
"有奖活动",
"反馈功能"
]
ignored_ann_ids = [
@ -74,8 +82,8 @@ def cache(ttl=timedelta(hours=1), arg_key=None):
@cache(ttl=timedelta(hours=3), arg_key='url')
async def query_data(url):
try:
resp = await get(url=url)
return resp.json()
req = await get(url)
return req.json()
except:
pass
return None
@ -84,8 +92,7 @@ async def query_data(url):
async def load_event_cn():
result = await query_data(url=list_api)
detail_result = await query_data(url=detail_api)
if result and 'retcode' in result and result['retcode'] == 0 and detail_result and 'retcode' in detail_result and \
detail_result['retcode'] == 0:
if result and 'retcode' in result and result['retcode'] == 0 and detail_result and 'retcode' in detail_result and detail_result['retcode'] == 0:
event_data['cn'] = []
event_detail = {}
for detail in detail_result['data']['list']:
@ -111,10 +118,8 @@ async def load_event_cn():
if ignore:
continue
start_time = datetime.strptime(
item['start_time'], r"%Y-%m-%d %H:%M:%S")
end_time = datetime.strptime(
item['end_time'], r"%Y-%m-%d %H:%M:%S")
start_time = datetime.strptime(item['start_time'], r"%Y-%m-%d %H:%M:%S")
end_time = datetime.strptime(item['end_time'], r"%Y-%m-%d %H:%M:%S")
# 从正文中查找开始时间
if event_detail[item["ann_id"]]:
@ -125,26 +130,35 @@ async def load_event_cn():
datelist = searchObj.groups() # ('2021', '9', '17')
if datelist and len(datelist) >= 6:
ctime = datetime.strptime(
f'{datelist[0]}-{datelist[1]}-{datelist[2]} {datelist[3]}:{datelist[4]}:{datelist[5]}',
r"%Y-%m-%d %H:%M:%S")
f'{datelist[0]}-{datelist[1]}-{datelist[2]} {datelist[3]}:{datelist[4]}:{datelist[5]}', r"%Y-%m-%d %H:%M:%S")
if start_time < ctime < end_time:
start_time = ctime
except Exception as e:
pass
event = {'title': item['title'],
'start': start_time,
'end': end_time,
'forever': False,
'type': 0}
event = {
'title': item['title'],
'start': start_time,
'end': end_time,
'forever': False,
'type': 0,
'banner': item['banner'],
'color': '#2196f3'
}
if '任务' in item['title']:
event['forever'] = True
event['color'] = '#f764ad'
event['banner'] = item['banner']
if item['type'] == 1:
event['type'] = 1
if '扭蛋' in item['tag_label']:
event['type'] = 2
if '' in item['title']:
event['color'] = '#ffc107'
event['banner'] = item['banner']
if '双倍' in item['title']:
event['type'] = 3
event['banner'] = item['banner']
event['color'] = '#580dda'
event_data['cn'].append(event)
# 深渊提醒
i = 0
@ -152,24 +166,24 @@ async def load_event_cn():
curmon = datetime.today() + relativedelta(months=i)
nextmon = curmon + relativedelta(months=1)
event_data['cn'].append({
'title': '「深境螺旋」',
'start': datetime.strptime(
curmon.strftime("%Y/%m/01 04:00"), r"%Y/%m/%d %H:%M"),
'end': datetime.strptime(
curmon.strftime("%Y/%m/16 03:59"), r"%Y/%m/%d %H:%M"),
'title': '「深境螺旋」· 上半段',
'start': datetime.strptime(curmon.strftime("%Y/%m/01 04:00"), r"%Y/%m/%d %H:%M"),
'end': datetime.strptime(curmon.strftime("%Y/%m/16 03:59"), r"%Y/%m/%d %H:%M"),
'forever': False,
'type': 3
'type': 3,
'color': '#580dda',
'banner': res + '/sy.jpg'
})
event_data['cn'].append({
'title': '「深境螺旋」',
'start': datetime.strptime(
curmon.strftime("%Y/%m/16 04:00"), r"%Y/%m/%d %H:%M"),
'end': datetime.strptime(
nextmon.strftime("%Y/%m/01 03:59"), r"%Y/%m/%d %H:%M"),
'title': '「深境螺旋」· 下半段 ',
'start': datetime.strptime(curmon.strftime("%Y/%m/16 04:00"), r"%Y/%m/%d %H:%M"),
'end': datetime.strptime(nextmon.strftime("%Y/%m/01 03:59"), r"%Y/%m/%d %H:%M"),
'forever': False,
'type': 3
'type': 3,
'color': '#580dda',
'banner': res + '/sy.jpg'
})
i = i + 1
i = i+1
return 0
return 1
@ -214,14 +228,12 @@ async def get_events(server, offset, days):
for event in event_data[server]:
if end > event['start'] and start < event['end']: # 在指定时间段内 已开始 且 未结束
event['start_days'] = math.ceil(
(event['start'] - start) / timedelta(days=1)) # 还有几天开始
event['left_days'] = math.floor(
(event['end'] - start) / timedelta(days=1)) # 还有几天结束
event['start_days'] = math.ceil((event['start'] - start) / timedelta(days=1)) # 还有几天开始
event['left_days'] = math.floor((event['end'] - start) / timedelta(days=1)) # 还有几天结束
events.append(event)
# 按type从大到小 按剩余天数从小到大
events.sort(key=lambda item: item["type"]
* 100 - item['left_days'], reverse=True)
events.sort(key=lambda item: item["type"] * 100 - item['left_days'], reverse=True)
return events
@ -229,6 +241,5 @@ if __name__ == '__main__':
async def main():
await load_event_cn()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -1,8 +1,16 @@
import base64
from io import BytesIO
from nonebot_plugin_htmlrender import html_to_pic
import jinja2
from .event import *
from .draw import *
body = []
template_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'Paimon_Calendar/template')
env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_path), enable_async=True)
def im2base64str(im):
io = BytesIO()
@ -12,34 +20,40 @@ def im2base64str(im):
async def generate_day_schedule(server='cn'):
events = await get_events(server, 0, 15)
events = await get_events(server, 0, 15)
has_prediction = False
""" 追加数据前先执行清除,以防数据叠加 """
body.clear()
for event in events:
if event['start_days'] > 0:
has_prediction = True
if has_prediction:
im = create_image(len(events) + 2)
else:
im = create_image(len(events) + 1)
title = f'原神日历'
pcr_now = get_pcr_now(0)
draw_title(im, 0, title, pcr_now.strftime('%Y/%m/%d'), '正在进行')
if len(events) == 0:
draw_item(im, 1, 1, '无数据', 0, False)
i = 1
template = env.get_template('calendar.html')
for event in events:
if event['start_days'] <= 0:
draw_item(im, i, event['type'], event['title'],
event['left_days'], event['forever'])
i += 1
time = '即将结束' if event["left_days"] == 0 else f'{str(event["left_days"])}天后结束'
body.append({
'title': event['title'],
'time': time,
'online': f'{datetime.strftime(event["start"], r"%m-%d")} ~ {datetime.strftime(event["end"], r"%m-%d")}',
'color': event['color'],
'banner': event['banner']
})
if has_prediction:
draw_title(im, i, right='即将开始')
for event in events:
if event['start_days'] > 0:
i += 1
draw_item(im, i, event['type'], event['title'], -
event['start_days'], event['forever'])
return im
time = '即将开始' if event["start_days"] == 0 else f'{str(event["start_days"])}天后开始'
body.append({
'title': event['title'],
'time': time,
'online': f'{datetime.strftime(event["start"], r"%m-%d")} ~ {datetime.strftime(event["end"], r"%m-%d")}',
'color': event['color'],
'banner': event['banner']
})
content = await template.render_async(body=body, css_path=template_path)
return await html_to_pic(content, wait=0, viewport={"width": 600, "height": 100})

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原神日历</title>
<link rel="stylesheet" href="{{ css_path }}/iview.css" />
<link rel="stylesheet" href="{{ css_path }}/index.css" />
</head>
<body>
<div class="calendar-wapper">
<div class="m-events-calendar">
<div class="m-events-calendar">
<div class="m-events-calenda__m-right">
{% for item in body %}
<div class="m-events-calendar__event-item-container" style="width: 535px; transform: translate(0px);">
<div class="m-events-calendar__event-item-bg" style="background-image: url('{{ item.banner }}');">
</div>
<div class="m-events-calendar__event-item-tag" style="background-color: {{ item.color }};">
</div>
<div class="m-events-calendar__event-item">
<div class="m-events-calendar__event-item-info">
<span class="m-events-calendar__event-item-act-name" title="{{ item.title }}">{{ item.title }}</span>
<!-- 格式一:开始结束日期为不同的日期 -->
<div class="m-events-calendar__event-item-text">{{ item.online }}</div>
<!-- 格式二:开始结束日期为同一个 --><!--v-if--><!-- 格式三:当天为结束日期 --><!--v-if--><!-- 格式四:当天为结束日期,且已经结束 --><!--v-if-->
</div><!-- 结束时间天数等于1切有结束时间 -->
<div class="m-events-calendar__event-item-end-time">{{ item.time }}</div>
</div>
</div>
{% endfor%}
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,333 @@
@import url("normalize.css");
@font-face {
font-family: "FFXIV-EN";
src: url("~/assets/font/EORZEA.TTF") format("truetype");
}
.xiv-en {
font-family: "FFXIV-EN", sans-serif;
}
.cursorAniDom {
content: " ";
transition: all 0.8s ease-out;
display: block;
position: absolute;
left: -0.25rem;
top: Calc(50% - 0.25rem);
width: 0.5rem;
height: 0.5rem;
background-repeat: no-repeat;
background-size: contain;
background-image: url("~assets/img/home/cursor.png");
-webkit-animation: 0.6s ease-out infinite running cursorAni;
animation: 0.6s ease-out infinite running cursorAni;
pointer-events: none;
}
@-webkit-keyframes cursorAni {
0% {
transform: translateX(0);
}
50% {
transform: translateX(0.03rem);
}
100% {
transform: translateX(0);
}
}
@keyframes cursorAni {
0% {
transform: translateX(0);
}
50% {
transform: translateX(0.03rem);
}
100% {
transform: translateX(0);
}
}
.tl-item,
.tl-item > div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.text-loop:hover > div {
white-space: nowrap;
-webkit-animation: 2s textLoop linear infinite alternate;
animation: 2s textLoop linear infinite alternate;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
}
@-webkit-keyframes textLoop {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(Calc(var(--text-width) - 100% - 0.5em));
}
}
@keyframes textLoop {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(Calc(var(--text-width) - 100% - 0.5em));
}
}
:root {
--bgColor: #161616;
}
body {
overflow: overlay;
}
.temp-def {
position: relative;
background-color: var(--bgColor);
}
.page-container {
min-width: calc(1000px + 80px * 2);
max-width: calc(1280px + 80px * 2);
margin: 0 auto;
padding: 0 80px;
background-color: var(--bgColor);
position: relative;
}
.ie-tips {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #161616;
}
.ie-tips__container {
width: 960px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.ie-tips__header {
height: 80px;
background-repeat: no-repeat;
background-size: 100%;
background-image: url(~assets/img/ie-tips/head.png);
}
.ie-tips__middle {
margin-top: -1px;
background-size: 100%;
background-image: url(~assets/img/ie-tips/middle.png);
text-align: center;
padding-bottom: 100px;
}
.ie-tips__bottom {
margin-top: -1px;
height: 89px;
background-repeat: no-repeat;
background-size: 100%;
background-image: url(~assets/img/ie-tips/bottom.png);
}
.ie-tips__content {
font-size: 16px;
}
.ie-tips__padding {
height: 50px;
}
.ie-tips__desc {
color: #9da2a2;
}
.ie-tips__img {
width: 121px;
position: absolute;
right: 100px;
bottom: 69px;
transform: rotate(16deg);
opacity: 0.8;
}
.ie-tips__sign {
font-family: "FFXIV-EN", sans-serif;
font-size: 20px;
position: absolute;
right: 93px;
bottom: 81px;
color: #63625e;
}
.m-events-calenda__m-right {
width: 532px;
background-color: #292b32;
position: relative;
padding-bottom: 1px;
border-radius: 10px;
box-shadow: 0 0 18px black;
}
.m-events-calendar__table-header {
display: flex;
background-color: #292b32;
position: relative;
border-radius: 10px 10px 0 0;
overflow: hidden;
}
.m-events-calendar__table-header-item {
width: 76px;
}
.m-events-calendar__table-header-week {
text-align: center;
padding-top: 10px;
}
.m-events-calendar__table-header-date {
text-align: center;
padding-bottom: 10px;
color: #e1e1e1;
}
.m-events-calendar__table-header-current {
background-color: #33343c;
}
.m-events-calendar__line-container {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
border-radius: 10px;
overflow: hidden;
}
.m-events-calendar__line-item {
width: 76px;
height: 100%;
position: relative;
}
.m-events-calendar__line-item::after {
content: '';
position: absolute;
right: -1px;
border-right: 1px dashed #cccccc21;
top: 0;
bottom: 0;
}
.m-events-calendar__line-item:last-of-type::after {
border-right-width: 0;
}
.m-events-calendar__line-item-current {
background-color: #33343c;
}
.m-events-calendar__line-item-last::after {
border-right-color: transparent;
}
.m-events-calendar__event-item-container {
height: 50px;
background-color: black;
position: relative;
left: -6px;
margin-bottom: 15px;
cursor: pointer;
display: block;
box-shadow: 4px 4px 4px rgba(35, 35, 35, 0.85);
}
.m-events-calendar__event-item-bg {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 100%;
background-position: center right;
background-size: auto 100%;
background-repeat: no-repeat;
-webkit-mask: linear-gradient(to right, transparent 50%, #000 100%);
mask: linear-gradient(to right, transparent 50%, #000 100%);
}
.m-events-calendar__event-item-tag {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 6px;
background-color: #5146c7;
}
.m-events-calendar__event-item {
padding-top: 8px;
padding-left: 13px;
position: relative;
}
.m-events-calendar__event-item-not-finish::after {
content: '';
position: absolute;
top: -6px;
right: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 6px 0 0 6px;
border-color: transparent transparent transparent #5d4f4f;
}
.m-events-calendar__event-item-info {
transform-origin: left top;
transform: scale(0.9);
}
.m-events-calendar__event-item-act-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 16px;
color: #ececec;
width: 100%;
display: block;
}
.m-events-calendar__event-item-text {
color: #bababa;
font-size: 12px;
}
.m-events-calendar__event-item-time {
font-size: 12px;
color: #ffc702;
}
.m-events-calendar__event-item-end-time {
position: absolute;
right: 16px;
font-size: 12px;
color: #e6e6e6;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
padding: 3px 6px;
transform-origin: top right;
transform: scale(0.9);
}
.m-events-calendar__event-item-end-time::before {
position: absolute;
top: 0;
left: -15px;
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 0 15px 21.6px 0;
border-color: transparent rgba(0, 0, 0, 0.5) transparent transparent;
}
.m-events-calendar__event-item-end-time::after {
position: absolute;
top: 0;
right: -15px;
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 21.6px 15px 0 0;
border-color: rgba(0, 0, 0, 0.5) transparent transparent transparent;
}
.calendar-wapper {
width: 600px;
background-color: #1e1d2c;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 50px;
padding-top: 30px;
}
.text {
text-align: center;
padding-top: 40px;
color: #5c6067;
}
.m-events-calendar__table-header-week {
color: #cecece;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB