😊优化代码结构,统一图片主题,优化总体质感,非常完美

This commit is contained in:
EillesWan 2025-01-22 12:15:07 +08:00
parent 049ca929f3
commit f417f829cc
8 changed files with 209 additions and 118 deletions

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"python.analysis.autoImportCompletions": true,
"python.analysis.typeCheckingMode": "standard"
}

View File

@ -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

View File

@ -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,

View File

@ -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)

View 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;
}

View File

@ -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);
}

View File

@ -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 }}");

View File

@ -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