mirror of
https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow.git
synced 2024-11-11 01:27:39 +08:00
commit
d5017e687f
15
README.md
15
README.md
@ -10,7 +10,6 @@
|
||||
|
||||
_✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
|
||||
|
||||
|
||||
<a href="./LICENSE">
|
||||
<img src="https://img.shields.io/github/license/LiteyukiStudio/nonebot-plugin-acgnshow.svg" alt="license">
|
||||
</a>
|
||||
@ -21,7 +20,6 @@ _✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## 📖 介绍
|
||||
|
||||
一个简单的 Nonebot2 插件,可以从哔哩哔哩会员购 API 获取展览(漫展等)的时间,地点,票价等信息。
|
||||
@ -44,21 +42,25 @@ _✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
|
||||
<summary>pip</summary>
|
||||
|
||||
pip install nonebot-plugin-acgnshow
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>pdm</summary>
|
||||
|
||||
pdm add nonebot-plugin-acgnshow
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>poetry</summary>
|
||||
|
||||
poetry add nonebot-plugin-acgnshow
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>conda</summary>
|
||||
|
||||
conda install nonebot-plugin-acgnshow
|
||||
|
||||
</details>
|
||||
|
||||
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
|
||||
@ -68,12 +70,13 @@ _✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
|
||||
</details>
|
||||
|
||||
## 🎉 使用
|
||||
|
||||
发送`展览`指令可以获取使用说明
|
||||
|
||||
## ⚙️ 配置
|
||||
|
||||
在 nonebot2 项目的`.env`文件中添加下表中的配置
|
||||
|
||||
| 配置项 | 必填 | 默认值 | 说明 |
|
||||
|:-----:|:----:|:----:|:----:|
|
||||
| ACGNSHOW_PAGESIZE | 否 | 8 | 单个图片的条目数,最大为20,条目数过大可能导致 Bot 无法发送 |
|
||||
|
||||
| 配置项 | 必填 | 默认值 | 说明 |
|
||||
| :---------------: | :--: | :----: | :----------------------------------------------------------: |
|
||||
| ACGNSHOW_PAGESIZE | 否 | 8 | 单个图片的条目数,最大为 20,条目数过大可能导致 Bot 无法发送 |
|
||||
|
@ -1,9 +1,11 @@
|
||||
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
|
||||
|
||||
usage = """命令格式:
|
||||
展览 <地区> [页码]
|
||||
或
|
||||
@ -27,8 +29,8 @@ __plugin_meta__ = PluginMetadata(
|
||||
config=ConfigModel,
|
||||
homepage="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow",
|
||||
supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"),
|
||||
#extra={"License":"MIT","Author":"Swankily"} snowykami的奇妙纠错(
|
||||
extra={"License":"MIT","Author":"Asankilp"}
|
||||
# extra={"License":"MIT","Author":"Swankily"} snowykami的奇妙纠错(
|
||||
extra={"License": "MIT", "Author": "Asankilp"},
|
||||
)
|
||||
driver = get_driver()
|
||||
|
||||
@ -36,4 +38,3 @@ driver = get_driver()
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
pass
|
||||
|
||||
|
@ -9,7 +9,7 @@ from .util import *
|
||||
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"
|
||||
"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"
|
||||
}
|
||||
|
||||
|
||||
@ -31,13 +31,8 @@ async def get_regions_dict() -> Dict[str, int]:
|
||||
city_data = await get_cities_data()
|
||||
for i in city_data.data.list:
|
||||
for j in i.city_list:
|
||||
data.update({
|
||||
j.name: j.id
|
||||
})
|
||||
data.update({
|
||||
"全国": -1,
|
||||
"海外": 900000
|
||||
})
|
||||
data.update({j.name: j.id})
|
||||
data.update({"全国": -1, "海外": 900000})
|
||||
return data
|
||||
|
||||
|
||||
@ -50,13 +45,13 @@ async def get_shows_data(region_id: int, page=1, pagesize=20):
|
||||
pagesize: 一页最大条目数,最大20
|
||||
"""
|
||||
param = {
|
||||
"version" : 133,
|
||||
"area" : region_id,
|
||||
"page" : page,
|
||||
"pagesize": pagesize,
|
||||
"platform": "web",
|
||||
"p_type" : "展览",
|
||||
"style" : 1
|
||||
"version": 133,
|
||||
"area": region_id,
|
||||
"page": page,
|
||||
"pagesize": pagesize,
|
||||
"platform": "web",
|
||||
"p_type": "展览",
|
||||
"style": 1,
|
||||
}
|
||||
async with ClientSession() as session:
|
||||
async with session.get(SHOWS_API_ROOT, headers=HEADERS, params=param) as resp:
|
||||
@ -108,30 +103,31 @@ def process_shows_data_to_template(shows_data: dict):
|
||||
district_name = i["district_name"]
|
||||
wish = i["wish"]
|
||||
cover = "https:" + i["cover"]
|
||||
if district_name == None: district_name = ""
|
||||
if district_name == None:
|
||||
district_name = ""
|
||||
guests_list = i["guests"]
|
||||
guests = ""
|
||||
if guests_list != None:
|
||||
for n in guests_list:
|
||||
guests += n["name"] + ","
|
||||
guests = "、".join(n["name"] for n in guests_list)
|
||||
else:
|
||||
guests = ""
|
||||
item_dict = {
|
||||
"name" : name,
|
||||
"location" : district_name + venue_name,
|
||||
"sale_flag" : sale_flag,
|
||||
"id" : project_id,
|
||||
"price" : price_low,
|
||||
"start_time" : start_time,
|
||||
"end_time" : end_time,
|
||||
"wish" : wish,
|
||||
"image_url" : cover,
|
||||
"guests" : guests,
|
||||
"page" : page,
|
||||
"total_pages": total_pages
|
||||
"name": name,
|
||||
"location": district_name + venue_name,
|
||||
"sale_flag": sale_flag,
|
||||
"id": project_id,
|
||||
"price": price_low,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time,
|
||||
"wish": wish,
|
||||
"image_url": cover,
|
||||
"guests": guests,
|
||||
"page": page,
|
||||
"total_pages": total_pages,
|
||||
}
|
||||
showlist.append(item_dict)
|
||||
global_data_dict = {
|
||||
"page" : page,
|
||||
"total_pages" : total_pages,
|
||||
"total_results": total_results
|
||||
"page": page,
|
||||
"total_pages": total_pages,
|
||||
"total_results": total_results,
|
||||
}
|
||||
return [showlist, global_data_dict]
|
||||
|
@ -20,36 +20,44 @@ showcmd = on_alconna(
|
||||
showcmd.shortcut(
|
||||
r"(?P<region>.+?)展览\s*(?P<page>\d+)?\s*(?P<date>.+)?",
|
||||
{
|
||||
"prefix" : True,
|
||||
"command": "展览",
|
||||
"args" : ["{region}", "{page}", "{date}"],
|
||||
}
|
||||
"prefix": True,
|
||||
"command": "展览",
|
||||
"args": ["{region}", "{page}", "{date}"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@showcmd.handle()
|
||||
async def find_show(
|
||||
region: Optional[str] = None, page: Optional[int] = None, date: Optional[str] = None,
|
||||
region: Optional[str] = None,
|
||||
page: Optional[int] = None,
|
||||
date: Optional[str] = None,
|
||||
):
|
||||
if not region: await UniMessage(__plugin_meta__.usage).send(); return
|
||||
if not page: page = 1
|
||||
if not date: date = ""
|
||||
if not region:
|
||||
await UniMessage(__plugin_meta__.usage).send()
|
||||
return
|
||||
if not page:
|
||||
page = 1
|
||||
if not date:
|
||||
date = ""
|
||||
regions_dict = await get_regions_dict()
|
||||
regionid = regions_dict.get(region, None)
|
||||
if regionid == None: await UniMessage("不支持此地区").send(); return
|
||||
if regionid == None:
|
||||
await UniMessage("地区未寻得或输入格式错误").send()
|
||||
return
|
||||
# await showcmd.send("日期:"+ date)
|
||||
shows = await get_shows_data(regionid, page=page, pagesize=config.acgnshow_pagesize)
|
||||
# print(shows)
|
||||
try:
|
||||
shows_data = process_shows_data_to_template(shows)
|
||||
template = {
|
||||
"shows" : shows_data[0],
|
||||
"bgimage" : choose_random_bgimage(),
|
||||
"global_data": shows_data[1]
|
||||
"shows": shows_data[0],
|
||||
"bgimage": choose_random_bgimage(),
|
||||
"global_data": shows_data[1],
|
||||
}
|
||||
pic = await template_to_pic(RES_PATH, TEMPLATE_NAME, template)
|
||||
pic = await template_to_pic(str(RES_PATH), TEMPLATE_NAME, template)
|
||||
except Exception as e:
|
||||
await UniMessage("发生错误").send()
|
||||
await UniMessage("图片生成时产生未知错误").send()
|
||||
traceback.print_exc()
|
||||
return
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
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):
|
||||
acgnshow_pagesize: int = 8
|
||||
|
||||
|
||||
config: ConfigModel = get_plugin_config(ConfigModel)
|
@ -17,6 +17,7 @@ class City(BaseModel):
|
||||
"""
|
||||
热门城市
|
||||
"""
|
||||
|
||||
id: int
|
||||
type: int
|
||||
first_letter: str
|
||||
@ -31,6 +32,7 @@ class CityDataList(BaseModel):
|
||||
"""
|
||||
城市首字母
|
||||
"""
|
||||
|
||||
letter: str
|
||||
city_list: List[City]
|
||||
|
||||
@ -39,6 +41,7 @@ class CityData(BaseModel):
|
||||
"""
|
||||
城市数据
|
||||
"""
|
||||
|
||||
hot: List[City]
|
||||
list: List[CityDataList]
|
||||
located_id: int
|
||||
@ -48,6 +51,7 @@ class CityResp(BaseModel):
|
||||
"""
|
||||
城市数据
|
||||
"""
|
||||
|
||||
errno: int
|
||||
errtag: int
|
||||
msg: str
|
||||
|
@ -1,17 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta charset="UTF-8" />
|
||||
<title>Show Information</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Source Han Sans';
|
||||
src: url('SourceHanSans.otf') format('opentype');
|
||||
font-family: "Source Han Sans";
|
||||
src: url("SourceHanSans.otf") format("opentype");
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Source Han Sans', sans-serif;
|
||||
background-image: url('{{ bgimage }}');
|
||||
font-family: "Source Han Sans", sans-serif;
|
||||
background-image: url("{{ bgimage }}");
|
||||
}
|
||||
|
||||
.background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@ -22,14 +25,17 @@
|
||||
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); /* 半透明白色背景 */
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
/* 半透明白色背景 */
|
||||
}
|
||||
|
||||
.header {
|
||||
border: 1px solid black;
|
||||
padding: 5px;
|
||||
@ -38,6 +44,7 @@
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
border: 1px solid black;
|
||||
@ -46,13 +53,15 @@
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 148px;
|
||||
height: 200px;
|
||||
border: 1px solid black;
|
||||
width: 149px;
|
||||
height: 201px;
|
||||
border: 1px solid rgba(128, 64, 128, 0.5);
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
@ -62,26 +71,32 @@
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.details .title {
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.details .venue_name {
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.details .guests {
|
||||
font-size: 10px;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap; /* 自动换行 */
|
||||
white-space: pre-wrap;
|
||||
/* 自动换行 */
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.details .placeholder {
|
||||
font-size: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.details .sale_flag {
|
||||
color: red;
|
||||
font-size: 10px;
|
||||
@ -89,6 +104,7 @@
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.details .id {
|
||||
color: black;
|
||||
font-size: 10px;
|
||||
@ -96,34 +112,40 @@
|
||||
top: 20px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.details .price {
|
||||
color: #FB7299;
|
||||
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;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border: 1px solid black;
|
||||
flex: 1;
|
||||
@ -134,40 +156,53 @@
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.footer .designer {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.footer .pages {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.footer .total_results {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.footer .project_name {
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
color: rgb(50, 227, 227);
|
||||
}
|
||||
|
||||
.footer .notice_text {
|
||||
position: relative;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
color: slateblue;
|
||||
}
|
||||
</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">
|
||||
<img src="{{ show.image_url }}" alt="Image" width="147px" height="199px" />
|
||||
</div>
|
||||
<div class="details">
|
||||
<div class="title">{{ show.name }}</div>
|
||||
@ -186,11 +221,17 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="footer">
|
||||
<div class="designer"> Designed by Asankilp? </div>
|
||||
<div class="total_results">共 {{ global_data.total_results }} 个结果</div>
|
||||
<div class="pages">{{ global_data.page }} / {{ global_data.total_pages }} 页</div>
|
||||
<div class="designer">Designed by Asankilp?</div>
|
||||
<div class="total_results">
|
||||
共 {{ global_data.total_results }} 个结果
|
||||
</div>
|
||||
<div class="pages">
|
||||
{{ global_data.page }} / {{ global_data.total_pages }} 页
|
||||
</div>
|
||||
<div class="project_name">nonebot-plugin-acgnshow</div>
|
||||
<div class="notice_text">本页信息仅供参考,具体内容请访问展览官方详情页,并自行检索实际信息</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,15 +1,21 @@
|
||||
from .config import BGIMAGE_PATH
|
||||
import os
|
||||
import random
|
||||
import datetime
|
||||
|
||||
from .config import BGIMAGE_PATH
|
||||
|
||||
def choose_random_bgimage():
|
||||
randomfile = random.choice(list(BGIMAGE_PATH.iterdir()))
|
||||
randomurl = randomfile.as_uri()
|
||||
|
||||
def choose_random_bgimage() -> str:
|
||||
"""
|
||||
从背景图片文件夹中随机选择一张图片,返回图片的uri地址
|
||||
"""
|
||||
randomfile = random.choice(os.listdir(BGIMAGE_PATH))
|
||||
randomurl = (BGIMAGE_PATH / randomfile).as_uri()
|
||||
return randomurl
|
||||
|
||||
|
||||
def convert_timestamp(timestamp):
|
||||
obj = datetime.datetime.fromtimestamp(timestamp)
|
||||
formatted_time = obj.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return formatted_time
|
||||
def convert_timestamp(timestamp) -> str:
|
||||
"""
|
||||
将时间戳转换为日期格式
|
||||
"""
|
||||
return datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
@ -4,9 +4,7 @@ version = "0.1.5"
|
||||
description = "Nonebot2插件,从哔哩哔哩会员购获取简易展览数据"
|
||||
readme = "README.md"
|
||||
requires-python = "<4.0,>=3.9"
|
||||
authors = [
|
||||
{ name = "Asankilp", email = "asankilp@outlook.com" },
|
||||
]
|
||||
authors = [{ name = "Asankilp", email = "asankilp@outlook.com" }]
|
||||
dependencies = [
|
||||
"nonebot2[fastapi, websockets]>=2.2.0",
|
||||
"nonebot-plugin-alconna>=0.48.0",
|
||||
|
Loading…
Reference in New Issue
Block a user