mirror of
https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow.git
synced 2025-06-01 09:45:28 +00:00
😊优化代码结构,统一图片主题,优化总体质感,非常完美
This commit is contained in:
parent
049ca929f3
commit
f417f829cc
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"python.analysis.autoImportCompletions": true,
|
||||
"python.analysis.typeCheckingMode": "standard"
|
||||
}
|
@ -58,35 +58,35 @@ async def get_shows_data(region_id: int, page=1, pagesize=20):
|
||||
shows_data = await resp.json()
|
||||
return shows_data
|
||||
|
||||
|
||||
async def get_show_details(show_id: int):
|
||||
param = {
|
||||
"id": show_id,
|
||||
"project_id": show_id,
|
||||
"requestSource": "neul-next"
|
||||
}
|
||||
param = {"id": show_id, "project_id": show_id, "requestSource": "neul-next"}
|
||||
async with ClientSession() as session:
|
||||
async with session.get(SHOW_DETAILS_API_ROOT, headers=HEADERS, params=param) as resp:
|
||||
async with session.get(
|
||||
SHOW_DETAILS_API_ROOT, headers=HEADERS, params=param
|
||||
) as resp:
|
||||
show_details_data = await resp.json()
|
||||
return show_details_data
|
||||
|
||||
def process_show_details_data_to_template(show_details_data: dict):
|
||||
|
||||
def process_show_details_data_to_template(show_details_data: dict) -> tuple:
|
||||
data = show_details_data["data"]
|
||||
|
||||
banner_url = "https:"+data["banner"]
|
||||
|
||||
banner_url = "https:" + data["banner"]
|
||||
# banner_url = extract_banner_url(data["performance_image"])
|
||||
|
||||
|
||||
# 提取事件基本信息
|
||||
name = data["name"]
|
||||
start_time = convert_timestamp(data["start_time"])
|
||||
end_time = convert_timestamp(data["end_time"])
|
||||
|
||||
|
||||
# 提取场馆信息
|
||||
venue_name = data["venue_info"]["name"]
|
||||
venue_detail = data["venue_info"]["address_detail"]
|
||||
|
||||
|
||||
# 提取主办方信息
|
||||
organizer = data["merchant"]["company"]
|
||||
|
||||
|
||||
# 提取实名制,退票等信息
|
||||
is_refund = data["is_refund"]
|
||||
id_bind = data["id_bind"]
|
||||
@ -96,21 +96,24 @@ def process_show_details_data_to_template(show_details_data: dict):
|
||||
ticket_info = []
|
||||
for screen in data.get("screen_list", []):
|
||||
for ticket in screen.get("ticket_list", []):
|
||||
ticket_info.append({
|
||||
"description": ticket.get("desc", ""),
|
||||
"price": ticket.get("price", 0),
|
||||
"sale_start": convert_timestamp(ticket.get("saleStart", 0)),
|
||||
"sale_end": convert_timestamp(ticket.get("saleEnd", 0)),
|
||||
"status": ticket.get("sale_flag", {}).get("display_name", ""),
|
||||
"screen_name": ticket.get("screen_name")
|
||||
})
|
||||
ticket_info.append(
|
||||
{
|
||||
"description": ticket.get("desc", ""),
|
||||
"price": ticket.get("price", 0),
|
||||
"sale_start": convert_timestamp(ticket.get("saleStart", 0)),
|
||||
"sale_end": convert_timestamp(ticket.get("saleEnd", 0)),
|
||||
"status": ticket.get("sale_flag", {}).get("display_name", ""),
|
||||
"screen_name": ticket.get("screen_name"),
|
||||
}
|
||||
)
|
||||
guests_list = data["guests"]
|
||||
if guests_list != None:
|
||||
guests = "、".join(n["name"] for n in guests_list)
|
||||
else:
|
||||
guests = ""
|
||||
|
||||
|
||||
desc = data["performance_desc"]["list"]
|
||||
details_html = "" # 可能未绑定
|
||||
for item in desc:
|
||||
if item.get("module") == "activity_content":
|
||||
details_html = item.get("details", "")
|
||||
@ -129,12 +132,13 @@ def process_show_details_data_to_template(show_details_data: dict):
|
||||
"is_refund": is_refund,
|
||||
"id_bind": id_bind,
|
||||
"has_eticket": has_eticket,
|
||||
"details_html": details_html
|
||||
"details_html": details_html,
|
||||
}
|
||||
|
||||
return [item_dict, details_html]
|
||||
|
||||
def process_shows_data_to_template(shows_data: dict):
|
||||
return item_dict, details_html
|
||||
|
||||
|
||||
def process_shows_data_to_template(shows_data: dict) -> tuple:
|
||||
showlist = []
|
||||
data = shows_data["data"]
|
||||
page = data["page"]
|
||||
@ -184,4 +188,5 @@ def process_shows_data_to_template(shows_data: dict):
|
||||
"total_pages": total_pages,
|
||||
"total_results": total_results,
|
||||
}
|
||||
return [showlist, global_data_dict]
|
||||
# return (sorted(showlist, key=lambda x: x["start_time"]), global_data_dict)
|
||||
return showlist, global_data_dict
|
||||
|
@ -39,15 +39,19 @@ showcmd_details.shortcut(
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@showcmd_details.handle()
|
||||
async def get_show_details_cmd(
|
||||
id: Optional[int] = None
|
||||
):
|
||||
async def get_show_details_cmd(id: Optional[int] = None):
|
||||
if not id:
|
||||
await UniMessage("请输入展览ID").send()
|
||||
return
|
||||
show_details = await get_show_details(id)
|
||||
if show_details["errno"] != 0: await UniMessage("发生错误").send() ; return
|
||||
if show_details["errno"] != 0:
|
||||
await UniMessage("发生{}号错误".format(show_details["errno"])).send()
|
||||
return
|
||||
try:
|
||||
show_details_data = process_show_details_data_to_template(show_details)
|
||||
#print(show_details_data)
|
||||
# print(show_details_data)
|
||||
template = {
|
||||
"show": show_details_data[0],
|
||||
"bgimage": choose_random_bgimage(),
|
||||
@ -59,15 +63,22 @@ async def get_show_details_cmd(
|
||||
return
|
||||
await UniMessage.image(raw=pic).send()
|
||||
if config.acgnshow_send_show_details_html:
|
||||
details_html_fragments = split_html_into_fragments(add_https_to_urls(show_details_data[1]))
|
||||
details_html_groups = join_fragments_in_groups(details_html_fragments, config.acgnshow_show_details_html_img_count)
|
||||
#print(details_html_groups)
|
||||
#print(details_html)
|
||||
details_html_fragments = split_html_into_fragments(
|
||||
add_https_to_urls(show_details_data[1])
|
||||
)
|
||||
details_html_groups = join_fragments_in_groups(
|
||||
details_html_fragments, config.acgnshow_show_details_html_img_count
|
||||
)
|
||||
# print(details_html_groups)
|
||||
# print(details_html)
|
||||
for html in details_html_groups:
|
||||
html_pic = await html_to_pic(html=html, device_scale_factor=config.acgnshow_show_details_html_scale)
|
||||
#print(html_pic)
|
||||
html_pic = await html_to_pic(
|
||||
html=html, device_scale_factor=config.acgnshow_show_details_html_scale
|
||||
)
|
||||
# print(html_pic)
|
||||
await UniMessage.image(raw=html_pic).send()
|
||||
|
||||
|
||||
@showcmd.handle()
|
||||
async def find_shows_cmd(
|
||||
region: Optional[str] = None,
|
||||
|
@ -10,9 +10,10 @@ BGIMAGE_PATH = RES_PATH / "bgimage"
|
||||
|
||||
class ConfigModel(BaseModel):
|
||||
acgnshow_pagesize: int = 10
|
||||
acgnshow_bgimage_path: str = BGIMAGE_PATH
|
||||
acgnshow_bgimage_path: str = BGIMAGE_PATH.resolve().as_posix()
|
||||
acgnshow_send_show_details_html: bool = False
|
||||
acgnshow_show_details_html_scale: float = 0.6
|
||||
acgnshow_show_details_html_img_count: int = 2
|
||||
|
||||
|
||||
config: ConfigModel = get_plugin_config(ConfigModel)
|
||||
|
80
nonebot_plugin_acgnshow/res/css/detail.css
Normal file
80
nonebot_plugin_acgnshow/res/css/detail.css
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
.detail_content {
|
||||
display: flex;
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
height: 201px;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(183, 207, 255, 0.5); /* 半透明白色背景 */
|
||||
}
|
||||
|
||||
.vector_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: bottom;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
margin-bottom: 15px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.45); /* 为 banner 添加边框 */
|
||||
display: flex;
|
||||
justify-content: center; /* 居中对齐图片 */
|
||||
align-items: center; /* 垂直居中对齐图片 */
|
||||
}
|
||||
|
||||
.banner img {
|
||||
width: 450px;
|
||||
height: 253px;
|
||||
}
|
||||
|
||||
.details .ticket_box {
|
||||
display: inline-block; /* 根据内容的宽度自动调整 */
|
||||
border: rgba(0, 0, 0, 0.15);
|
||||
background-color: rgba(109, 146, 220, 0.15); /* 半透明蓝白色背景 */
|
||||
/* border-radius: 15px; 圆角半径 谁允许你圆了 */
|
||||
padding: 15px; /* 内边距 */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影以增强视觉效果 */
|
||||
text-align: center; /* 内容水平居中 */
|
||||
width: auto; /* 根据内容宽度自动调整 */
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative; /* 使子元素绝对定位相对于这个父元素 */
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.details .title {
|
||||
font-weight: bold; /* 加粗字体 */
|
||||
margin-bottom: 5px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
|
||||
.details .status {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.details .start-time {
|
||||
position: absolute;
|
||||
bottom: 20px; /* 与end-time有一定的高度差异 */
|
||||
right: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.details .end-time {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
@ -22,13 +22,13 @@ body {
|
||||
width: 98%;
|
||||
margin: 1%;
|
||||
padding: 10px;
|
||||
border: 1px solid #fff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(255, 255, 255, 0.8); /* 半透明白色背景 */
|
||||
background-color: rgba(255, 255, 255, 0.5); /* 半透明白色背景 */
|
||||
}
|
||||
|
||||
.header {
|
||||
border: 1px solid black;
|
||||
border: 1px solid rgba(0, 0, 0, 0.45);
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
@ -38,21 +38,12 @@ body {
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
border: 1px solid black;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.detail_content {
|
||||
display: flex;
|
||||
border: 1px solid black;
|
||||
height: 201px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(183, 207, 255, 0.25); /* 半透明白色背景 */
|
||||
}
|
||||
|
||||
.image {
|
||||
@ -63,48 +54,19 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vector_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: bottom;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
margin-bottom: 15px;
|
||||
border: 2px solid #000; /* 为 banner 添加边框 */
|
||||
display: flex;
|
||||
justify-content: center; /* 居中对齐图片 */
|
||||
align-items: center; /* 垂直居中对齐图片 */
|
||||
}
|
||||
|
||||
.banner img {
|
||||
width: 450px;
|
||||
height: 253px;
|
||||
}
|
||||
|
||||
.details .ticket_box {
|
||||
display: inline-block; /* 根据内容的宽度自动调整 */
|
||||
background-color: rgba(255, 255, 255, 0.1); /* 半透明白色背景 */
|
||||
border-radius: 15px; /* 圆角半径 */
|
||||
padding: 20px; /* 内边距 */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影以增强视觉效果 */
|
||||
text-align: center; /* 内容水平居中 */
|
||||
width: auto; /* 根据内容宽度自动调整 */
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative; /* 使子元素绝对定位相对于这个父元素 */
|
||||
font-size: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.details .title {
|
||||
font-weight: bold; /* 加粗字体 */
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.details .venue_name,
|
||||
@ -116,14 +78,14 @@ body {
|
||||
.details .sale_flag {
|
||||
color: red;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
top: 15px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.details .id {
|
||||
color: black;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
top: 30px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
@ -135,33 +97,31 @@ body {
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.details .status {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.details .wish {
|
||||
color: gray;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 80px; /* 适当调整以避免与price重叠 */
|
||||
left: 90px; /* 适当调整以避免与price重叠 */
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.details .start-time {
|
||||
position: absolute;
|
||||
bottom: 20px; /* 与end-time有一定的高度差异 */
|
||||
right: 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.details .end-time {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border: 1px solid black;
|
||||
margin-top: 15px;
|
||||
border: 1px solid rgb(0, 0, 0, 0.25);
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
@ -179,30 +139,30 @@ body {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.footer .pages,
|
||||
.footer .total_results {
|
||||
.footer .total_results,
|
||||
.footer .pages {
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.footer .pages {
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.footer .total_results {
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.footer .pages {
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.footer .project_name {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
color: rgb(50, 227, 227);
|
||||
color: rgb(34, 154, 154);
|
||||
}
|
||||
|
||||
.footer .notice_text {
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
color: slateblue;
|
||||
color: rgb(81, 69, 159);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<title>Show Details</title>
|
||||
<link rel="stylesheet" href="./css/style.css" />
|
||||
<link rel="stylesheet" href="./css/detail.css" />
|
||||
<style>
|
||||
body {
|
||||
background-image: url("{{ bgimage }}");
|
||||
|
@ -1,4 +1,3 @@
|
||||
import os
|
||||
import re
|
||||
import random
|
||||
import datetime
|
||||
@ -7,30 +6,58 @@ from pathlib import Path
|
||||
from .config import config
|
||||
|
||||
|
||||
bgpath: Path = Path(config.acgnshow_bgimage_path)
|
||||
bg_list: list[Path] = [
|
||||
f
|
||||
for f in bgpath.iterdir()
|
||||
if f.suffix
|
||||
in (
|
||||
".jpg",
|
||||
".png",
|
||||
".jpeg",
|
||||
".gif",
|
||||
".webp",
|
||||
".bmp",
|
||||
".svg",
|
||||
".ico",
|
||||
".tiff",
|
||||
".tif",
|
||||
".jfif",
|
||||
".jpe",
|
||||
".jif",
|
||||
".jfi",
|
||||
".jfif",
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def choose_random_bgimage() -> str:
|
||||
"""
|
||||
从背景图片文件夹中随机选择一张图片,返回图片的uri地址
|
||||
从背景图片文件夹中随机选择一张图片,返回图片的file协议uri地址
|
||||
"""
|
||||
bgpath = Path(config.acgnshow_bgimage_path)
|
||||
randomfile = random.choice(os.listdir(bgpath))
|
||||
randomurl = (bgpath / randomfile).as_uri()
|
||||
return randomurl
|
||||
# randomfile = random.choice(os.listdir(bgpath)) # 天哪
|
||||
|
||||
return random.choice(bg_list).as_uri()
|
||||
|
||||
|
||||
def convert_timestamp(timestamp) -> str:
|
||||
def convert_timestamp(timestamp, strformat: str = "%Y-%m-%d %H:%M:%S") -> str:
|
||||
"""
|
||||
将时间戳转换为日期格式
|
||||
|
||||
:param timestamp: unix 时间戳
|
||||
:param strformat: 日期格式,默认为 "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
:return: yyyy-mm-dd hh:mm:ss时间
|
||||
"""
|
||||
return datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||
return datetime.datetime.fromtimestamp(timestamp).strftime(strformat)
|
||||
|
||||
|
||||
def extract_banner_url(value) -> str:
|
||||
a = json.loads(value)
|
||||
url = "https:"+a["banner"]["url"]
|
||||
url = "https:" + a["banner"]["url"]
|
||||
return url
|
||||
|
||||
|
||||
def add_https_to_urls(html_content):
|
||||
"""
|
||||
为 HTML 内容中的缺失 https: 前缀的 URL 添加 https: 前缀
|
||||
@ -39,9 +66,10 @@ def add_https_to_urls(html_content):
|
||||
:return: 修正后的 HTML 字符串
|
||||
"""
|
||||
# 使用正则表达式查找所有以 "//" 开头的 URL
|
||||
updated_html_content = re.sub(r'(?<=src=["\'])//', 'https://', html_content)
|
||||
updated_html_content = re.sub(r'(?<=src=["\'])//', "https://", html_content)
|
||||
return updated_html_content
|
||||
|
||||
|
||||
def split_html_into_fragments(html_content):
|
||||
"""
|
||||
将 HTML 内容按照元素分割成多个片段,并存储在列表中
|
||||
@ -50,10 +78,11 @@ def split_html_into_fragments(html_content):
|
||||
:return: 存储 HTML 片段的列表
|
||||
"""
|
||||
# 使用正则表达式匹配 HTML 标签及其内容
|
||||
pattern = re.compile(r'(<[^>]+>[^<]*<\/[^>]+>|<[^>]+\/>|<[^>]+>)')
|
||||
pattern = re.compile(r"(<[^>]+>[^<]*<\/[^>]+>|<[^>]+\/>|<[^>]+>)")
|
||||
fragments = pattern.findall(html_content)
|
||||
return fragments
|
||||
|
||||
|
||||
def join_fragments_in_groups(fragments, image_count=2):
|
||||
"""
|
||||
|
||||
@ -67,10 +96,10 @@ def join_fragments_in_groups(fragments, image_count=2):
|
||||
for group in fragments:
|
||||
buffer += group
|
||||
if "img" in group:
|
||||
count += 1 # 发现图片则计数器+1
|
||||
count += 1 # 发现图片则计数器+1
|
||||
if count >= image_count:
|
||||
grouped_html.append(buffer)
|
||||
count = 0
|
||||
buffer = "" # 初始化计数器和缓冲区
|
||||
grouped_html.append(buffer)# 把缓冲区剩余内容一起添加
|
||||
return grouped_html
|
||||
buffer = "" # 初始化计数器和缓冲区
|
||||
grouped_html.append(buffer) # 把缓冲区剩余内容一起添加
|
||||
return grouped_html
|
||||
|
Loading…
x
Reference in New Issue
Block a user