初次提交

This commit is contained in:
Asankilp 2024-07-11 10:26:21 +00:00
parent 728aa8bebf
commit 05c6119369
17 changed files with 374 additions and 0 deletions

View File

@ -0,0 +1,22 @@
from nonebot.plugin import PluginMetadata, inherit_supported_adapters, require
require("nonebot_plugin_htmlrender")
require("nonebot_plugin_alconna")
from .acgnshower import *
from nonebot import get_driver
from .config import ConfigModel
__author__ = "Asankilp"
__plugin_meta__ = PluginMetadata(
name="漫展/展览查询",
description="从哔哩哔哩会员购获取简易展览数据",
usage="application",
config=ConfigModel,
homepage="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow",
supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna")
)
driver = get_driver()
@driver.on_startup
async def _():
pass

View File

@ -0,0 +1,99 @@
import json
import requests
from nonebot_plugin_htmlrender import template_to_pic
from jinja2 import Template
CITY_API_ROOT="https://show.bilibili.com/api/ticket/city/list?channel=3"
SHOWS_API_ROOT="https://show.bilibili.com/api/ticket/project/listV2"
HEADERS = {
"user-agent": "Mozilla/5.0 (Linux; Android 14; 114514YAJU Build/UKQ1.114514.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/125.0.6422.165 Mobile Safari/537.36 BiliApp/7810200 mobi_app/android isNotchWindow/0 NotchHeight=34 mallVersion/7810200 mVersion/242 disable_rcmd/0 7.81.0 os/android model/114514YAJU mobi_app/android build/7810200 channel/bilih5 innerVer/7810210 osVer/14 network/2"
}
def get_regions_data():
'''
返回支持的地区数据
'''
regions_data = json.loads(requests.get(CITY_API_ROOT, headers=HEADERS).text)
return regions_data
def get_regions_dict():
'''
返回支持的地区键名为地区名键值为地区id
'''
dicts = {}
cityjson = get_regions_data()
for i in cityjson["data"]["list"]:
for j in i["city_list"]:
name = j["name"]
id = j["id"]
dicts.update({name: id})
dicts.update({"全国": -1,"海外": 900000}) #添加api中未返回的结果
#print(dicts)
return dicts
def get_shows_data(region_id: int, page=1, pagesize=20):
'''
返回举办中/即将举办/取消举办的展览数据
Args:
region_id: 地区id
page: 页码
pagesize: 一页最大条目数最大20
'''
param = {
"version": 133,
"area": region_id,
"page": page,
"pagesize": pagesize,
"platform": "web",
"p_type": "展览",
"style": 1
}
shows_data = json.loads(requests.get(SHOWS_API_ROOT, headers=HEADERS,params=param).text)
return shows_data
def process_shows_data_to_text(shows_data: dict):
showlist = []
for i in shows_data["data"]["result"]:
name = i["project_name"]
venue_name = i["venue_name"]
project_id = i["project_id"]
sale_flag = i["sale_flag"]
start_time = i["start_time"]
end_time = i["end_time"]
price_low = i["price_low"] / 100
price_high = i["price_high"] / 100
district_name = i["district_name"]
text = f"名称:{name}\n举办地:{venue_name}\nid:{project_id}\nflag:{sale_flag}\n开始时间:{start_time}\n结束时间:{end_time}\n最低票价:{price_low}\n最高票价:{price_high}\n区名:{district_name}\n\n"
showlist.append(text)
return showlist
def read_template_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
def process_shows_data_to_template(shows_data: dict):
showlist = []
# show_template = read_template_file('/home/asankilp/LiteyukiBot/src/plugins/acgnshow/res/template.html')
for i in shows_data["data"]["result"]:
name = i["project_name"]
venue_name = i["venue_name"]
project_id = i["project_id"]
sale_flag = i["sale_flag"]
start_time = i["start_time"]
end_time = i["end_time"]
price_low = i["price_low"] / 100
price_high = i["price_high"] / 100
district_name = i["district_name"]
wish = i["wish"]
cover = "https:" + i["cover"]
if district_name == None : district_name = ""
dicts = {}
dicts.update({
"name": name,
"location": district_name + venue_name,
"sale_flag": sale_flag,
"price": price_low,
"start_time": start_time,
"end_time": end_time,
"wish": wish,
"image_url": cover
})
showlist.append(dicts)
return showlist
template = Template(show_template)
rendered = template.render(exhibitions=showlist)
return rendered

View File

@ -0,0 +1,49 @@
from nonebot import require, on_endswith
from nonebot.adapters import satori
from nonebot.adapters.onebot.v11 import MessageSegment
from nonebot.typing import T_State
from typing import Optional
from .acgnapis import *
from nonebot_plugin_htmlrender import text_to_pic, template_to_pic
from nonebot_plugin_alconna import on_alconna
from arclet.alconna import Alconna, Args
from .config import RES_PATH, TEMPLATE_NAME, config
from .util import *
showcmd = on_alconna(
Alconna(
"展览",
Args["region?", str]["page?", int]["date?", str],
)
)
showcmd.shortcut(
r"(?P<region>.+?)展览\s*(?P<page>\d+)?\s*(?P<date>.+)?",
{
"prefix": True,
"command": "展览",
"args": ["{region}", "{page}", "{date}"],
}
)
@showcmd.handle()
async def find_show(
state: T_State, region: Optional[str] = None, page: Optional[int] = None, date: Optional[str] = None,
):
if not region: await showcmd.finish("未指定地区")
if not page: page = 1
if not date: date = ""
regions_dict = get_regions_dict()
regionid = regions_dict.get(region,None)
if regionid == None: await showcmd.finish("未找到此地区") ; return
#await showcmd.send("日期:"+ date)
shows = get_shows_data(regionid,page=page,pagesize=config.pagesize)
# print(shows)
template = {
"shows":process_shows_data_to_template(shows),
"bgimage": choose_random_bgimage()
}
pic = await template_to_pic(RES_PATH,TEMPLATE_NAME,template)
# print(pic)
# a = Image.open(io.BytesIO(pic))
# a.save("template2pic.png", format="PNG")
await showcmd.finish(MessageSegment.image(pic))

View File

@ -0,0 +1,11 @@
from pathlib import Path
from pydantic import BaseModel
from nonebot import get_plugin_config
RES_PATH = Path(__file__).parent / "res"
TEMPLATE_NAME = "template.html"
BGIMAGE_PATH = RES_PATH / "bgimage"
class ConfigModel(BaseModel):
pagesize: int = 8
config: ConfigModel = get_plugin_config(ConfigModel)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View File

@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Show Information</title>
<style>
@font-face {
font-family: 'Source Han Sans';
src: url('SourceHanSans.otf') format('opentype');
}
body {
font-family: 'Source Han Sans', sans-serif;
background-image: url('{{ bgimage }}');
}
.background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
/*background-image: url('{{ bgimage }}');*/
background-size: cover;
filter: blur(40%);
z-index: -1;
}
.container {
width: 98%;
margin: 1%;
border: 1px solid #fff;
padding: 10px;
box-sizing: border-box;
background-color: rgba(255, 255, 255, 0.8); /* 半透明白色背景 */
}
.header {
border: 1px solid black;
padding: 5px;
margin-bottom: 10px;
text-align: center;
font-size: 10px;
font-weight: bold;
}
.content {
display: flex;
border: 1px solid black;
margin-bottom: 10px;
padding: 5px;
position: relative;
box-sizing: border-box;
}
.image {
width: 148px;
height: 200px;
border: 1px solid black;
text-align: center;
/*padding: 10px; */
box-sizing: border-box;
}
.details {
flex: 1;
padding-left: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
font-size: 10px;
}
.details .title {
font-size: 10px;
font-weight: bold;
}
.details .venue_name {
font-size: 10px;
font-weight: normal;
}
.details .sale_flag {
color: red;
font-size: 10px;
position: absolute;
top: 5px;
right: 5px;
}
.details .price {
color: #FB7299;
font-size: 10px;
font-weight: bold;
position: absolute;
bottom: 5px;
left: 5px;
}
.details .wish {
color: gray;
position: absolute;
bottom: 5px;
left: 60px;
}
.details .start-time,
.details .end-time {
font-size: 10px;
}
.details .start-time {
position: absolute;
bottom: 20px;
right: 5px;
}
.details .end-time {
position: absolute;
bottom: 5px;
right: 5px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">展览信息</div>
{% for show in shows %}
<div class="content">
<div class="image">
<img src="{{ show.image_url }}" alt="Image" width="148" height="200">
</div>
<div class="details">
<div class="title">
<div>{{ show.name }}</div>
<div class="venue_name">
<div>举办地点:{{ show.location }}</div>
</div>
</div>
<div class="sale_flag">{{ show.sale_flag }}</div>
<div class="price">¥{{ show.price }}起</div>
<div class="wish">{{ show.wish }}人想去</div>
<div class="start-time">开始时间:{{ show.start_time }}</div>
<div class="end-time">结束时间:{{ show.end_time }}</div>
</div>
</div>
{% endfor %}
<div class="header">
Designed by Asankilp?
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,3 @@
from nonebot.adapters.onebot import v11, v12
from nonebot.adapters import satori
T_MessageEvent = v11.MessageEvent | v12.MessageEvent | satori.MessageEvent

View File

@ -0,0 +1,6 @@
from .config import BGIMAGE_PATH
import random
from pathlib import Path
def choose_random_bgimage():
randomfile = random.choice(list(BGIMAGE_PATH.iterdir()))
return str(randomfile)

43
pyproject.toml Normal file
View File

@ -0,0 +1,43 @@
[project]
name = "nonebot-plugin-acgnshow"
version = "0.1.0"
description = "Nonebot2插件从哔哩哔哩会员购获取简易展览数据"
readme = "README.md"
requires-python = "<4.0,>=3.8"
authors = [
{name = "Asankilp", email = "asankilp@outlook.com"},
]
dependencies = [
"nonebot2>=2.2.0",
"nonebot-plugin-alconna>=0.48.0",
"nonebot-plugin-htmlrender>=0.3.2",
"jinja2>=3.1.4",
]
license = {text = "MIT"}
[tool.nonebot]
plugins = ["nonebot_plugin_acgnshow"]
adapters = [
{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }
]
[tool.poetry.dependencies]
python = "^3.8"
nonebot2 = { version = "^2.2.0", extras = ["fastapi"] }
nonebot-plugin-alconna = ">=0.38.0,<1.0.0"
[tool.pdm]
distribution = true
[tool.pdm.version]
source = "file"
path = "nonebot_plugin_acgnshow/__init__.py"
[tool.pdm.build]
includes = []
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

0
tests/__init__.py Normal file
View File