nonebot-plugin-acgnshow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 LiteyukiStudio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.1
2
+ Name: nonebot-plugin-acgnshow
3
+ Version: 0.1.0
4
+ Summary: Nonebot2插件,从哔哩哔哩会员购获取简易展览数据
5
+ Author-Email: Asankilp <asankilp@outlook.com>
6
+ License: MIT
7
+ Requires-Python: <4.0,>=3.8
8
+ Requires-Dist: nonebot2>=2.2.0
9
+ Requires-Dist: nonebot-plugin-alconna>=0.48.0
10
+ Requires-Dist: nonebot-plugin-htmlrender>=0.3.2
11
+ Requires-Dist: jinja2>=3.1.4
12
+ Description-Content-Type: text/markdown
13
+
14
+ <div align="center">
15
+ <a href="https://v2.nonebot.dev/store"><img src="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow/blob/resources/nbp_logo.png" width="180" height="180" alt="NoneBotPluginLogo"></a>
16
+ <br>
17
+ <p><img src="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow/blob/resources/NoneBotPlugin.svg" width="240" alt="NoneBotPluginText"></p>
18
+ </div>
19
+
20
+ <div align="center">
21
+
22
+ # nonebot-plugin-acgnshow
23
+
24
+ _✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
25
+
26
+
27
+ <a href="./LICENSE">
28
+ <img src="https://img.shields.io/github/license/LiteyukiStudio/nonebot-plugin-acgnshow.svg" alt="license">
29
+ </a>
30
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-acgnshow">
31
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-acgnshow.svg" alt="pypi">
32
+ </a>
33
+ <img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
34
+
35
+ </div>
36
+
37
+
38
+ ## 📖 介绍
39
+
40
+ 一个简单的 Nonebot2 插件,可以从哔哩哔哩会员购 API 获取展览(漫展等)的时间,地点,票价等信息。
41
+
42
+ ## 💿 安装
43
+
44
+ <details open>
45
+ <summary>使用 nb-cli 安装</summary>
46
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
47
+
48
+ nb plugin install nonebot-plugin-acgnshow
49
+
50
+ </details>
51
+
52
+ <details>
53
+ <summary>使用包管理器安装</summary>
54
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
55
+
56
+ <details>
57
+ <summary>pip</summary>
58
+
59
+ pip install nonebot-plugin-acgnshow
60
+ </details>
61
+ <details>
62
+ <summary>pdm</summary>
63
+
64
+ pdm add nonebot-plugin-acgnshow
65
+ </details>
66
+ <details>
67
+ <summary>poetry</summary>
68
+
69
+ poetry add nonebot-plugin-acgnshow
70
+ </details>
71
+ <details>
72
+ <summary>conda</summary>
73
+
74
+ conda install nonebot-plugin-acgnshow
75
+ </details>
76
+
77
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
78
+
79
+ plugins = ["nonebot_plugin_acgnshow"]
80
+
81
+ </details>
82
+
83
+ ## 🎉 使用
84
+ 发送`展览`指令可以获取使用说明
85
+ ## ⚙️ 配置
86
+
87
+ 在 nonebot2 项目的`.env`文件中添加下表中的配置
88
+
89
+ | 配置项 | 必填 | 默认值 | 说明 |
90
+ |:-----:|:----:|:----:|:----:|
91
+ | ACGNSHOW_PAGESIZE | 否 | 8 | 单个图片的条目数,最大为20,条目数过大可能导致 Bot 无法发送 |
92
+
@@ -0,0 +1,79 @@
1
+ <div align="center">
2
+ <a href="https://v2.nonebot.dev/store"><img src="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow/blob/resources/nbp_logo.png" width="180" height="180" alt="NoneBotPluginLogo"></a>
3
+ <br>
4
+ <p><img src="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow/blob/resources/NoneBotPlugin.svg" width="240" alt="NoneBotPluginText"></p>
5
+ </div>
6
+
7
+ <div align="center">
8
+
9
+ # nonebot-plugin-acgnshow
10
+
11
+ _✨ 从哔哩哔哩会员购获取展览简易信息 ✨_
12
+
13
+
14
+ <a href="./LICENSE">
15
+ <img src="https://img.shields.io/github/license/LiteyukiStudio/nonebot-plugin-acgnshow.svg" alt="license">
16
+ </a>
17
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-acgnshow">
18
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-acgnshow.svg" alt="pypi">
19
+ </a>
20
+ <img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
21
+
22
+ </div>
23
+
24
+
25
+ ## 📖 介绍
26
+
27
+ 一个简单的 Nonebot2 插件,可以从哔哩哔哩会员购 API 获取展览(漫展等)的时间,地点,票价等信息。
28
+
29
+ ## 💿 安装
30
+
31
+ <details open>
32
+ <summary>使用 nb-cli 安装</summary>
33
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
34
+
35
+ nb plugin install nonebot-plugin-acgnshow
36
+
37
+ </details>
38
+
39
+ <details>
40
+ <summary>使用包管理器安装</summary>
41
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
42
+
43
+ <details>
44
+ <summary>pip</summary>
45
+
46
+ pip install nonebot-plugin-acgnshow
47
+ </details>
48
+ <details>
49
+ <summary>pdm</summary>
50
+
51
+ pdm add nonebot-plugin-acgnshow
52
+ </details>
53
+ <details>
54
+ <summary>poetry</summary>
55
+
56
+ poetry add nonebot-plugin-acgnshow
57
+ </details>
58
+ <details>
59
+ <summary>conda</summary>
60
+
61
+ conda install nonebot-plugin-acgnshow
62
+ </details>
63
+
64
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
65
+
66
+ plugins = ["nonebot_plugin_acgnshow"]
67
+
68
+ </details>
69
+
70
+ ## 🎉 使用
71
+ 发送`展览`指令可以获取使用说明
72
+ ## ⚙️ 配置
73
+
74
+ 在 nonebot2 项目的`.env`文件中添加下表中的配置
75
+
76
+ | 配置项 | 必填 | 默认值 | 说明 |
77
+ |:-----:|:----:|:----:|:----:|
78
+ | ACGNSHOW_PAGESIZE | 否 | 8 | 单个图片的条目数,最大为20,条目数过大可能导致 Bot 无法发送 |
79
+
@@ -0,0 +1,36 @@
1
+ from nonebot.plugin import PluginMetadata, inherit_supported_adapters, require
2
+ require("nonebot_plugin_htmlrender")
3
+ require("nonebot_plugin_alconna")
4
+ from .acgnshower import *
5
+ from nonebot import get_driver
6
+ from .config import ConfigModel
7
+ usage = """命令格式:
8
+ 展览 <地区> [页码]
9
+ 或
10
+ <地区>展览 [页码]
11
+ 其中地区为省级行政区或地级行政区(不包含后缀)
12
+ (如北京,福建,平顶山,绍兴,香港...,或海外/全国)
13
+
14
+ 示例:
15
+ 展览 福建 2
16
+ 福建展览 2
17
+ 全国展览
18
+ 海外展览"""
19
+ __author__ = "Asankilp"
20
+ __plugin_meta__ = PluginMetadata(
21
+ name="漫展/展览查询",
22
+ description="从哔哩哔哩会员购获取简易展览数据",
23
+ usage=usage,
24
+ type="application",
25
+ config=ConfigModel,
26
+ homepage="https://github.com/LiteyukiStudio/nonebot-plugin-acgnshow",
27
+ supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"),
28
+ extra={"License":"MIT","Author":"Asankilp"}
29
+ )
30
+ driver = get_driver()
31
+
32
+
33
+ @driver.on_startup
34
+ async def _():
35
+ pass
36
+
@@ -0,0 +1,99 @@
1
+ import json
2
+ import requests
3
+ from nonebot_plugin_htmlrender import template_to_pic
4
+ from jinja2 import Template
5
+ CITY_API_ROOT="https://show.bilibili.com/api/ticket/city/list?channel=3"
6
+ SHOWS_API_ROOT="https://show.bilibili.com/api/ticket/project/listV2"
7
+ HEADERS = {
8
+ "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"
9
+ }
10
+ def get_regions_data():
11
+ '''
12
+ 返回支持的地区数据
13
+ '''
14
+ regions_data = json.loads(requests.get(CITY_API_ROOT, headers=HEADERS).text)
15
+ return regions_data
16
+ def get_regions_dict():
17
+ '''
18
+ 返回支持的地区,键名为地区名,键值为地区id
19
+ '''
20
+ dicts = {}
21
+ cityjson = get_regions_data()
22
+ for i in cityjson["data"]["list"]:
23
+ for j in i["city_list"]:
24
+ name = j["name"]
25
+ id = j["id"]
26
+ dicts.update({name: id})
27
+ dicts.update({"全国": -1,"海外": 900000}) #添加api中未返回的结果
28
+ #print(dicts)
29
+ return dicts
30
+ def get_shows_data(region_id: int, page=1, pagesize=20):
31
+ '''
32
+ 返回举办中/即将举办/取消举办的展览数据
33
+ Args:
34
+ region_id: 地区id
35
+ page: 页码
36
+ pagesize: 一页最大条目数,最大20
37
+ '''
38
+ param = {
39
+ "version": 133,
40
+ "area": region_id,
41
+ "page": page,
42
+ "pagesize": pagesize,
43
+ "platform": "web",
44
+ "p_type": "展览",
45
+ "style": 1
46
+ }
47
+ shows_data = json.loads(requests.get(SHOWS_API_ROOT, headers=HEADERS,params=param).text)
48
+ return shows_data
49
+ def process_shows_data_to_text(shows_data: dict):
50
+ showlist = []
51
+ for i in shows_data["data"]["result"]:
52
+ name = i["project_name"]
53
+ venue_name = i["venue_name"]
54
+ project_id = i["project_id"]
55
+ sale_flag = i["sale_flag"]
56
+ start_time = i["start_time"]
57
+ end_time = i["end_time"]
58
+ price_low = i["price_low"] / 100
59
+ price_high = i["price_high"] / 100
60
+ district_name = i["district_name"]
61
+ 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"
62
+ showlist.append(text)
63
+ return showlist
64
+ def read_template_file(file_path):
65
+ with open(file_path, 'r', encoding='utf-8') as file:
66
+ return file.read()
67
+
68
+ def process_shows_data_to_template(shows_data: dict):
69
+ showlist = []
70
+ # show_template = read_template_file('/home/asankilp/LiteyukiBot/src/plugins/acgnshow/res/template.html')
71
+ for i in shows_data["data"]["result"]:
72
+ name = i["project_name"]
73
+ venue_name = i["venue_name"]
74
+ project_id = i["project_id"]
75
+ sale_flag = i["sale_flag"]
76
+ start_time = i["start_time"]
77
+ end_time = i["end_time"]
78
+ price_low = i["price_low"] / 100
79
+ price_high = i["price_high"] / 100
80
+ district_name = i["district_name"]
81
+ wish = i["wish"]
82
+ cover = "https:" + i["cover"]
83
+ if district_name == None : district_name = ""
84
+ dicts = {}
85
+ dicts.update({
86
+ "name": name,
87
+ "location": district_name + venue_name,
88
+ "sale_flag": sale_flag,
89
+ "price": price_low,
90
+ "start_time": start_time,
91
+ "end_time": end_time,
92
+ "wish": wish,
93
+ "image_url": cover
94
+ })
95
+ showlist.append(dicts)
96
+ return showlist
97
+ template = Template(show_template)
98
+ rendered = template.render(exhibitions=showlist)
99
+ return rendered
@@ -0,0 +1,49 @@
1
+ from nonebot import require, on_endswith
2
+ from nonebot.adapters import satori
3
+ from nonebot.adapters.onebot.v11 import MessageSegment
4
+ from nonebot.typing import T_State
5
+ from typing import Optional
6
+ from .acgnapis import *
7
+ from nonebot_plugin_htmlrender import text_to_pic, template_to_pic
8
+ from nonebot_plugin_alconna import on_alconna
9
+ from arclet.alconna import Alconna, Args
10
+ from .config import RES_PATH, TEMPLATE_NAME, config
11
+ from .util import *
12
+ from .__init__ import __plugin_meta__
13
+ showcmd = on_alconna(
14
+ Alconna(
15
+ "展览",
16
+ Args["region?", str]["page?", int]["date?", str],
17
+ )
18
+ )
19
+ showcmd.shortcut(
20
+ r"(?P<region>.+?)展览\s*(?P<page>\d+)?\s*(?P<date>.+)?",
21
+ {
22
+ "prefix": True,
23
+ "command": "展览",
24
+ "args": ["{region}", "{page}", "{date}"],
25
+ }
26
+ )
27
+
28
+ @showcmd.handle()
29
+ async def find_show(
30
+ state: T_State, region: Optional[str] = None, page: Optional[int] = None, date: Optional[str] = None,
31
+ ):
32
+ if not region: await showcmd.finish(__plugin_meta__.usage)
33
+ if not page: page = 1
34
+ if not date: date = ""
35
+ regions_dict = get_regions_dict()
36
+ regionid = regions_dict.get(region,None)
37
+ if regionid == None: await showcmd.finish("未找到此地区") ; return
38
+ #await showcmd.send("日期:"+ date)
39
+ shows = get_shows_data(regionid,page=page,pagesize=config.acgnshow_pagesize)
40
+ # print(shows)
41
+ template = {
42
+ "shows":process_shows_data_to_template(shows),
43
+ "bgimage": choose_random_bgimage()
44
+ }
45
+ pic = await template_to_pic(RES_PATH,TEMPLATE_NAME,template)
46
+ # print(pic)
47
+ # a = Image.open(io.BytesIO(pic))
48
+ # a.save("template2pic.png", format="PNG")
49
+ await showcmd.finish(MessageSegment.image(pic))
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+ from pydantic import BaseModel
3
+ from nonebot import get_plugin_config
4
+ RES_PATH = Path(__file__).parent / "res"
5
+ TEMPLATE_NAME = "template.html"
6
+ BGIMAGE_PATH = RES_PATH / "bgimage"
7
+
8
+ class ConfigModel(BaseModel):
9
+ acgnshow_pagesize: int = 8
10
+
11
+ config: ConfigModel = get_plugin_config(ConfigModel)
@@ -0,0 +1,141 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Show Information</title>
6
+ <style>
7
+ @font-face {
8
+ font-family: 'Source Han Sans';
9
+ src: url('SourceHanSans.otf') format('opentype');
10
+ }
11
+ body {
12
+ font-family: 'Source Han Sans', sans-serif;
13
+ background-image: url('{{ bgimage }}');
14
+
15
+ }
16
+ .background {
17
+ position: fixed;
18
+ top: 0;
19
+ left: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ /*background-image: url('{{ bgimage }}');*/
23
+ background-size: cover;
24
+ filter: blur(40%);
25
+ z-index: -1;
26
+ }
27
+ .container {
28
+ width: 98%;
29
+ margin: 1%;
30
+ border: 1px solid #fff;
31
+ padding: 10px;
32
+ box-sizing: border-box;
33
+ background-color: rgba(255, 255, 255, 0.8); /* 半透明白色背景 */
34
+ }
35
+ .header {
36
+ border: 1px solid black;
37
+ padding: 5px;
38
+ margin-bottom: 10px;
39
+ text-align: center;
40
+ font-size: 10px;
41
+ font-weight: bold;
42
+ }
43
+ .content {
44
+ display: flex;
45
+ border: 1px solid black;
46
+ margin-bottom: 10px;
47
+ padding: 5px;
48
+ position: relative;
49
+ box-sizing: border-box;
50
+ }
51
+ .image {
52
+ width: 148px;
53
+ height: 200px;
54
+ border: 1px solid black;
55
+ text-align: center;
56
+ /*padding: 10px; */
57
+ box-sizing: border-box;
58
+ }
59
+ .details {
60
+ flex: 1;
61
+ padding-left: 10px;
62
+ display: flex;
63
+ flex-direction: column;
64
+ justify-content: space-between;
65
+ position: relative;
66
+ font-size: 10px;
67
+ }
68
+ .details .title {
69
+ font-size: 10px;
70
+ font-weight: bold;
71
+ }
72
+ .details .venue_name {
73
+ font-size: 10px;
74
+ font-weight: normal;
75
+ }
76
+ .details .sale_flag {
77
+ color: red;
78
+ font-size: 10px;
79
+ position: absolute;
80
+ top: 5px;
81
+ right: 5px;
82
+ }
83
+ .details .price {
84
+ color: #FB7299;
85
+ font-size: 10px;
86
+ font-weight: bold;
87
+ position: absolute;
88
+ bottom: 5px;
89
+ left: 5px;
90
+ }
91
+ .details .wish {
92
+ color: gray;
93
+ position: absolute;
94
+ bottom: 5px;
95
+ left: 60px;
96
+ }
97
+ .details .start-time,
98
+ .details .end-time {
99
+ font-size: 10px;
100
+ }
101
+ .details .start-time {
102
+ position: absolute;
103
+ bottom: 20px;
104
+ right: 5px;
105
+ }
106
+ .details .end-time {
107
+ position: absolute;
108
+ bottom: 5px;
109
+ right: 5px;
110
+ }
111
+ </style>
112
+ </head>
113
+ <body>
114
+ <div class="container">
115
+ <div class="header">展览信息</div>
116
+ {% for show in shows %}
117
+ <div class="content">
118
+ <div class="image">
119
+ <img src="{{ show.image_url }}" alt="Image" width="148" height="200">
120
+ </div>
121
+ <div class="details">
122
+ <div class="title">
123
+ <div>{{ show.name }}</div>
124
+ <div class="venue_name">
125
+ <div>举办地点:{{ show.location }}</div>
126
+ </div>
127
+ </div>
128
+ <div class="sale_flag">{{ show.sale_flag }}</div>
129
+ <div class="price">¥{{ show.price }}起</div>
130
+ <div class="wish">{{ show.wish }}人想去</div>
131
+ <div class="start-time">开始时间:{{ show.start_time }}</div>
132
+ <div class="end-time">结束时间:{{ show.end_time }}</div>
133
+ </div>
134
+ </div>
135
+ {% endfor %}
136
+ <div class="header">
137
+ Designed by Asankilp?
138
+ </div>
139
+ </div>
140
+ </body>
141
+ </html>
@@ -0,0 +1,3 @@
1
+ from nonebot.adapters.onebot import v11, v12
2
+ from nonebot.adapters import satori
3
+ T_MessageEvent = v11.MessageEvent | v12.MessageEvent | satori.MessageEvent
@@ -0,0 +1,6 @@
1
+ from .config import BGIMAGE_PATH
2
+ import random
3
+ from pathlib import Path
4
+ def choose_random_bgimage():
5
+ randomfile = random.choice(list(BGIMAGE_PATH.iterdir()))
6
+ return str(randomfile)
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "nonebot-plugin-acgnshow"
3
+ version = "0.1.0"
4
+ description = "Nonebot2插件,从哔哩哔哩会员购获取简易展览数据"
5
+ readme = "README.md"
6
+ requires-python = "<4.0,>=3.8"
7
+ authors = [
8
+ { name = "Asankilp", email = "asankilp@outlook.com" },
9
+ ]
10
+ dependencies = [
11
+ "nonebot2>=2.2.0",
12
+ "nonebot-plugin-alconna>=0.48.0",
13
+ "nonebot-plugin-htmlrender>=0.3.2",
14
+ "jinja2>=3.1.4",
15
+ ]
16
+
17
+ [project.license]
18
+ text = "MIT"
19
+
20
+ [tool.nonebot]
21
+ plugins = [
22
+ "nonebot_plugin_acgnshow",
23
+ ]
24
+ adapters = [
25
+ { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
26
+ ]
27
+
28
+ [tool.pdm]
29
+ distribution = true
30
+
31
+ [tool.pdm.version]
32
+ source = "file"
33
+ path = "nonebot_plugin_acgnshow/__init__.py"
34
+
35
+ [tool.pdm.build]
36
+ includes = []
37
+
38
+ [build-system]
39
+ requires = [
40
+ "pdm-backend",
41
+ ]
42
+ build-backend = "pdm.backend"
File without changes