nonebot-plugin-aawarframe 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.
- nonebot_plugin_aawarframe-0.1.0/LICENSE +21 -0
- nonebot_plugin_aawarframe-0.1.0/PKG-INFO +100 -0
- nonebot_plugin_aawarframe-0.1.0/README.md +85 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/__init__.py +39 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/core/data_source.py +17 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_fetcher.py +9 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_processor.py +181 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_sources/__init__.py +38 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_sources/conquest_base.py +23 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_sources/deep_archimedea.py +10 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/data_sources/temporal_archimedea.py +10 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/renderers/__init__.py +25 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe/renderers/html_renderer.py +111 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe.egg-info/PKG-INFO +100 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe.egg-info/SOURCES.txt +18 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe.egg-info/dependency_links.txt +1 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe.egg-info/requires.txt +4 -0
- nonebot_plugin_aawarframe-0.1.0/nonebot_plugin_aawarframe.egg-info/top_level.txt +1 -0
- nonebot_plugin_aawarframe-0.1.0/pyproject.toml +15 -0
- nonebot_plugin_aawarframe-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aameow
|
|
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,100 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nonebot-plugin-aawarframe
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Default template for PDM package
|
|
5
|
+
Author-email: nekox41 <aameow@outlook.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: ==3.12.*
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: nonebot2>=2.5.0
|
|
11
|
+
Requires-Dist: httpx~=0.28.1
|
|
12
|
+
Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc5
|
|
13
|
+
Requires-Dist: nonebot-adapter-onebot>=2.4.6
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
<div align="center">
|
|
17
|
+
<a href="https://v2.nonebot.dev/store"><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.png" width="180" height="180" alt="aawarframeLogo"></a>
|
|
18
|
+
<br>
|
|
19
|
+
<p><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.svg" width="240" alt="aawarframeLogo"></p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div align="center">
|
|
23
|
+
|
|
24
|
+
# nonebot-plugin-aawarframe
|
|
25
|
+
|
|
26
|
+
_✨ Aa 的 Warframe 助手,用于查询游戏状态。 ✨_
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<a href="./LICENSE">
|
|
30
|
+
<img src="https://img.shields.io/github/license/nekox41/nonebot-plugin-aawarframe.svg" alt="license">
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://pypi.python.org/pypi/nonebot-plugin-aawarframe">
|
|
33
|
+
<img src="https://img.shields.io/pypi/v/nonebot-plugin-aawarframe.svg" alt="pypi">
|
|
34
|
+
</a>
|
|
35
|
+
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
## 📖 介绍
|
|
40
|
+
|
|
41
|
+
这里是插件的详细介绍部分
|
|
42
|
+
|
|
43
|
+
## 💿 安装
|
|
44
|
+
|
|
45
|
+
<details open>
|
|
46
|
+
<summary>使用 nb-cli 安装</summary>
|
|
47
|
+
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
|
48
|
+
|
|
49
|
+
nb plugin install nonebot-plugin-aawarframe
|
|
50
|
+
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
<details>
|
|
54
|
+
<summary>使用包管理器安装</summary>
|
|
55
|
+
在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
|
|
56
|
+
|
|
57
|
+
<details>
|
|
58
|
+
<summary>pip</summary>
|
|
59
|
+
|
|
60
|
+
pip install nonebot-plugin-aawarframe
|
|
61
|
+
</details>
|
|
62
|
+
<details>
|
|
63
|
+
<summary>pdm</summary>
|
|
64
|
+
|
|
65
|
+
pdm add nonebot-plugin-aawarframe
|
|
66
|
+
</details>
|
|
67
|
+
<details>
|
|
68
|
+
<summary>poetry</summary>
|
|
69
|
+
|
|
70
|
+
poetry add nonebot-plugin-aawarframe
|
|
71
|
+
</details>
|
|
72
|
+
<details>
|
|
73
|
+
<summary>conda</summary>
|
|
74
|
+
|
|
75
|
+
conda install nonebot-plugin-aawarframe
|
|
76
|
+
</details>
|
|
77
|
+
|
|
78
|
+
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
|
|
79
|
+
|
|
80
|
+
plugins = ["nonebot_plugin_template"]
|
|
81
|
+
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
## ⚙️ 配置
|
|
85
|
+
|
|
86
|
+
在 nonebot2 项目的`.env`文件中添加下表中的必填配置
|
|
87
|
+
|
|
88
|
+
| 配置项 | 必填 | 默认值 | 说明 |
|
|
89
|
+
|:-----:|:----:|:----:|:----:|
|
|
90
|
+
| 配置项1 | 是 | 无 | 配置说明 |
|
|
91
|
+
| 配置项2 | 否 | 无 | 配置说明 |
|
|
92
|
+
|
|
93
|
+
## 🎉 使用
|
|
94
|
+
### 指令表
|
|
95
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
|
96
|
+
|:-----:|:----:|:----:|:----:|:----:|
|
|
97
|
+
| 指令1 | 主人 | 否 | 私聊 | 指令说明 |
|
|
98
|
+
| 指令2 | 群员 | 是 | 群聊 | 指令说明 |
|
|
99
|
+
### 效果图
|
|
100
|
+
如果有效果图的话
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://v2.nonebot.dev/store"><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.png" width="180" height="180" alt="aawarframeLogo"></a>
|
|
3
|
+
<br>
|
|
4
|
+
<p><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.svg" width="240" alt="aawarframeLogo"></p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
|
|
9
|
+
# nonebot-plugin-aawarframe
|
|
10
|
+
|
|
11
|
+
_✨ Aa 的 Warframe 助手,用于查询游戏状态。 ✨_
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
<a href="./LICENSE">
|
|
15
|
+
<img src="https://img.shields.io/github/license/nekox41/nonebot-plugin-aawarframe.svg" alt="license">
|
|
16
|
+
</a>
|
|
17
|
+
<a href="https://pypi.python.org/pypi/nonebot-plugin-aawarframe">
|
|
18
|
+
<img src="https://img.shields.io/pypi/v/nonebot-plugin-aawarframe.svg" alt="pypi">
|
|
19
|
+
</a>
|
|
20
|
+
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
## 📖 介绍
|
|
25
|
+
|
|
26
|
+
这里是插件的详细介绍部分
|
|
27
|
+
|
|
28
|
+
## 💿 安装
|
|
29
|
+
|
|
30
|
+
<details open>
|
|
31
|
+
<summary>使用 nb-cli 安装</summary>
|
|
32
|
+
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
|
33
|
+
|
|
34
|
+
nb plugin install nonebot-plugin-aawarframe
|
|
35
|
+
|
|
36
|
+
</details>
|
|
37
|
+
|
|
38
|
+
<details>
|
|
39
|
+
<summary>使用包管理器安装</summary>
|
|
40
|
+
在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
|
|
41
|
+
|
|
42
|
+
<details>
|
|
43
|
+
<summary>pip</summary>
|
|
44
|
+
|
|
45
|
+
pip install nonebot-plugin-aawarframe
|
|
46
|
+
</details>
|
|
47
|
+
<details>
|
|
48
|
+
<summary>pdm</summary>
|
|
49
|
+
|
|
50
|
+
pdm add nonebot-plugin-aawarframe
|
|
51
|
+
</details>
|
|
52
|
+
<details>
|
|
53
|
+
<summary>poetry</summary>
|
|
54
|
+
|
|
55
|
+
poetry add nonebot-plugin-aawarframe
|
|
56
|
+
</details>
|
|
57
|
+
<details>
|
|
58
|
+
<summary>conda</summary>
|
|
59
|
+
|
|
60
|
+
conda install nonebot-plugin-aawarframe
|
|
61
|
+
</details>
|
|
62
|
+
|
|
63
|
+
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
|
|
64
|
+
|
|
65
|
+
plugins = ["nonebot_plugin_template"]
|
|
66
|
+
|
|
67
|
+
</details>
|
|
68
|
+
|
|
69
|
+
## ⚙️ 配置
|
|
70
|
+
|
|
71
|
+
在 nonebot2 项目的`.env`文件中添加下表中的必填配置
|
|
72
|
+
|
|
73
|
+
| 配置项 | 必填 | 默认值 | 说明 |
|
|
74
|
+
|:-----:|:----:|:----:|:----:|
|
|
75
|
+
| 配置项1 | 是 | 无 | 配置说明 |
|
|
76
|
+
| 配置项2 | 否 | 无 | 配置说明 |
|
|
77
|
+
|
|
78
|
+
## 🎉 使用
|
|
79
|
+
### 指令表
|
|
80
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
|
81
|
+
|:-----:|:----:|:----:|:----:|:----:|
|
|
82
|
+
| 指令1 | 主人 | 否 | 私聊 | 指令说明 |
|
|
83
|
+
| 指令2 | 群员 | 是 | 群聊 | 指令说明 |
|
|
84
|
+
### 效果图
|
|
85
|
+
如果有效果图的话
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from nonebot import require
|
|
2
|
+
|
|
3
|
+
require("nonebot_plugin_htmlkit")
|
|
4
|
+
|
|
5
|
+
from nonebot.plugin import PluginMetadata
|
|
6
|
+
from nonebot import on_command
|
|
7
|
+
from nonebot.adapters.onebot.v11 import MessageSegment
|
|
8
|
+
from .data_sources import get_source
|
|
9
|
+
from .renderers import renderer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__plugin_meta__ = PluginMetadata(
|
|
13
|
+
name='nonebot-plugin-aawarframe',
|
|
14
|
+
description='aa 的 Warframe 插件',
|
|
15
|
+
usage="",
|
|
16
|
+
type="application",
|
|
17
|
+
extra={},
|
|
18
|
+
homepage="https://github.com/nekox41/nonebot-plugin-aawarframe",
|
|
19
|
+
supported_adapters={"~onebot.v11"}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# -----------------------
|
|
23
|
+
|
|
24
|
+
temporal_cmd = on_command("时光科研")
|
|
25
|
+
|
|
26
|
+
@temporal_cmd.handle()
|
|
27
|
+
async def temporal_cmd_handle():
|
|
28
|
+
temporal_source = get_source("temporal_archimedea")
|
|
29
|
+
data = await temporal_source.fetch()
|
|
30
|
+
img = await renderer.render(data, "archimedea","archimedea.html", "temporal.img")
|
|
31
|
+
await temporal_cmd.finish(MessageSegment.image(img))
|
|
32
|
+
|
|
33
|
+
deep_cmd = on_command("深层科研")
|
|
34
|
+
@deep_cmd.handle()
|
|
35
|
+
async def deep_cmd_handle():
|
|
36
|
+
deep_source = get_source("deep_archimedea")
|
|
37
|
+
data = await deep_source.fetch()
|
|
38
|
+
img = await renderer.render(data, "archimedea", "archimedea.html", "deep.img")
|
|
39
|
+
await deep_cmd.finish(MessageSegment.image(img))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ResearchDataSource(ABC):
|
|
6
|
+
"""所有数据源必须实现的抽象基类"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def command_name(self) -> str:
|
|
11
|
+
"""命令名称(如 'time_research'),用于路由和注册"""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def fetch(self) -> Dict[str, Any]:
|
|
16
|
+
"""获取并转换数据,返回最终用于渲染的字典"""
|
|
17
|
+
pass
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
async def fetch_world_state() -> Dict[str, Any]:
|
|
5
|
+
url = "https://api.warframe.com/cdn/worldState.php"
|
|
6
|
+
async with httpx.AsyncClient() as client:
|
|
7
|
+
resp = await client.get(url)
|
|
8
|
+
resp.raise_for_status()
|
|
9
|
+
return resp.json()
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Dict, List, Union
|
|
4
|
+
from nonebot.log import logger
|
|
5
|
+
|
|
6
|
+
# ---------- 加载映射文件 ----------
|
|
7
|
+
_ASSETS_DIR = Path(__file__).parent / "assets"
|
|
8
|
+
|
|
9
|
+
def _load_json(filename: str) -> Dict:
|
|
10
|
+
path = _ASSETS_DIR / filename
|
|
11
|
+
if path.exists():
|
|
12
|
+
with open(path, 'r', encoding='utf-8') as f:
|
|
13
|
+
return json.load(f)
|
|
14
|
+
return {}
|
|
15
|
+
|
|
16
|
+
FACTION_MAP = _load_json("faction_type.json") # 如 {"FC_SCALDRA": "炽蛇军"}
|
|
17
|
+
MISSION_TYPE_MAP = _load_json("mission_type.json") # 如 {"MT_DEFENSE": "防御"}
|
|
18
|
+
CONQUEST_ZH = _load_json("conquest_zh.json") # 所有字符串翻译
|
|
19
|
+
VARIABLES_MAP = _load_json("variables.json")
|
|
20
|
+
|
|
21
|
+
def _get_translation(key: str) -> str:
|
|
22
|
+
"""从 conquest_zh.json 获取翻译,若不存在则返回原 key"""
|
|
23
|
+
return CONQUEST_ZH.get(key, key)
|
|
24
|
+
|
|
25
|
+
# ---------- 核心转换函数 ----------
|
|
26
|
+
def transform_to_archimedea_data(raw_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
27
|
+
"""
|
|
28
|
+
将原始 Conquest 数据(包含 Type, Missions, Variables)转换为前端所需格式
|
|
29
|
+
"""
|
|
30
|
+
conquest_type = raw_data.get("Type", "")
|
|
31
|
+
if not conquest_type:
|
|
32
|
+
return {}
|
|
33
|
+
|
|
34
|
+
# 根据类型选择前缀
|
|
35
|
+
if conquest_type == "CT_LAB":
|
|
36
|
+
type_prefix = "/Lotus/Language/Conquest/MissionVariant_LabConquest_"
|
|
37
|
+
else: # CT_HEX 或其它
|
|
38
|
+
type_prefix = "/Lotus/Language/Conquest/MissionVariant_HexConquest_"
|
|
39
|
+
|
|
40
|
+
pm_prefix = "/Lotus/Language/Conquest/PersonalMod_"
|
|
41
|
+
risk_prefix = "/Lotus/Language/Conquest/Condition_"
|
|
42
|
+
|
|
43
|
+
# ---------- 处理 Missions ----------
|
|
44
|
+
missions = []
|
|
45
|
+
for mission in raw_data.get("Missions", []):
|
|
46
|
+
# 转换 faction 和 missionType
|
|
47
|
+
faction_key = mission.get("faction", "")
|
|
48
|
+
faction_zh = FACTION_MAP.get(faction_key, faction_key)
|
|
49
|
+
|
|
50
|
+
mission_type_key = mission.get("missionType", "")
|
|
51
|
+
mission_type_zh = MISSION_TYPE_MAP.get(mission_type_key, mission_type_key)
|
|
52
|
+
|
|
53
|
+
# 寻找 CD_HARD 难度的配置(若没有则尝试 CD_NORMAL)
|
|
54
|
+
difficulties = mission.get("difficulties", [])
|
|
55
|
+
hard_diff = None
|
|
56
|
+
for diff in difficulties:
|
|
57
|
+
if diff.get("type") == "CD_HARD":
|
|
58
|
+
hard_diff = diff
|
|
59
|
+
break
|
|
60
|
+
if hard_diff is None:
|
|
61
|
+
# 没有 CD_HARD,尝试 CD_NORMAL
|
|
62
|
+
for diff in difficulties:
|
|
63
|
+
if diff.get("type") == "CD_NORMAL":
|
|
64
|
+
hard_diff = diff
|
|
65
|
+
break
|
|
66
|
+
if hard_diff is None:
|
|
67
|
+
# 若仍没有则跳过该任务
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
# 构建条件列表
|
|
71
|
+
conditions = []
|
|
72
|
+
|
|
73
|
+
# a) deviation 作为一个条件
|
|
74
|
+
deviation = hard_diff.get("deviation")
|
|
75
|
+
if deviation:
|
|
76
|
+
name_key = type_prefix + deviation
|
|
77
|
+
desc_key = name_key + "_Desc"
|
|
78
|
+
conditions.append({
|
|
79
|
+
"name": _get_translation(name_key),
|
|
80
|
+
"desc": _get_translation(desc_key)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
# b) risks 中的每个风险作为一个条件
|
|
84
|
+
for risk in hard_diff.get("risks", []):
|
|
85
|
+
name_key = risk_prefix + risk
|
|
86
|
+
desc_key = name_key + "_Desc"
|
|
87
|
+
conditions.append({
|
|
88
|
+
"name": _get_translation(name_key),
|
|
89
|
+
"desc": _get_translation(desc_key)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
missions.append({
|
|
93
|
+
"faction": faction_zh,
|
|
94
|
+
"missionType": mission_type_zh,
|
|
95
|
+
"difficulties": conditions
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
# ---------- 处理 Variables(先转换 UI 名称为内部名称)----------
|
|
99
|
+
variables = []
|
|
100
|
+
for ui_name in raw_data.get("Variables", []):
|
|
101
|
+
# 根据 UI 名称查找内部名称
|
|
102
|
+
internal_name = VARIABLES_MAP.get(ui_name) # 若找不到则为 None
|
|
103
|
+
if internal_name is None:
|
|
104
|
+
# 如果映射中找不到,保留原样(或者记录日志,或者直接跳过)
|
|
105
|
+
# 这里我们保留原样并用它拼接(可能失败)
|
|
106
|
+
internal_name = ui_name
|
|
107
|
+
# 拼接前缀
|
|
108
|
+
name_key = pm_prefix + internal_name
|
|
109
|
+
desc_key = name_key + "_Desc"
|
|
110
|
+
variables.append({
|
|
111
|
+
"name": _get_translation(name_key),
|
|
112
|
+
"desc": _get_translation(desc_key)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
"Missions": missions,
|
|
117
|
+
"Variables": variables
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
def extract_conquests(raw_data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
121
|
+
"""
|
|
122
|
+
从 World State 中提取 Conquests (科研数据)
|
|
123
|
+
:param raw_data: World State 数据
|
|
124
|
+
:return: 两个科研的数据,可以通过 Type 来区分时光和深层。CT_LAB 为深层,CT_HEX 为时光。
|
|
125
|
+
"""
|
|
126
|
+
conquests = raw_data.get("Conquests", [])
|
|
127
|
+
if not conquests:
|
|
128
|
+
logger.warning("未找到科研数据。")
|
|
129
|
+
|
|
130
|
+
return conquests
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def render_archimedea_panel(data: Union[Dict, str], template_path: str = "archimedea.html") -> str:
|
|
134
|
+
"""
|
|
135
|
+
将任务数据填充到HTML模板中,返回完整的HTML字符串。
|
|
136
|
+
参数与之前一致。
|
|
137
|
+
"""
|
|
138
|
+
# 如果传入的是JSON字符串,先解析为字典
|
|
139
|
+
if isinstance(data, str):
|
|
140
|
+
data = json.loads(data)
|
|
141
|
+
|
|
142
|
+
# 构建左侧任务区域的HTML行
|
|
143
|
+
missions_rows = []
|
|
144
|
+
for mission in data.get("Missions", []):
|
|
145
|
+
mission_type = mission.get("missionType", "未知任务")
|
|
146
|
+
faction = mission.get("faction", "")
|
|
147
|
+
difficulties = mission.get("difficulties", [])
|
|
148
|
+
|
|
149
|
+
title_content = mission_type
|
|
150
|
+
if faction:
|
|
151
|
+
title_content += f' <span class="faction-tag">{faction}</span>'
|
|
152
|
+
|
|
153
|
+
missions_rows.append(f'<tr class="task-title-row"><td colspan="2">{title_content}</td></tr>')
|
|
154
|
+
|
|
155
|
+
for diff in difficulties:
|
|
156
|
+
cond_name = diff.get("name", "")
|
|
157
|
+
cond_desc = diff.get("desc", "")
|
|
158
|
+
missions_rows.append(
|
|
159
|
+
f'<tr>'
|
|
160
|
+
f'<td class="cond-name">{cond_name}</td>'
|
|
161
|
+
f'<td class="cond-desc">{cond_desc}</td>'
|
|
162
|
+
f'</tr>'
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# 构建右侧变量区域的HTML行
|
|
166
|
+
variables_rows = []
|
|
167
|
+
for var in data.get("Variables", []):
|
|
168
|
+
var_name = var.get("name", "")
|
|
169
|
+
var_desc = var.get("desc", "")
|
|
170
|
+
variables_rows.append(f'<tr class="factor-title-row"><td colspan="2">{var_name}</td></tr>')
|
|
171
|
+
variables_rows.append(f'<tr class="factor-desc-row"><td colspan="2">{var_desc}</td></tr>')
|
|
172
|
+
|
|
173
|
+
# 读取模板文件(注意路径)
|
|
174
|
+
template_path = Path(template_path) # 确保是Path对象
|
|
175
|
+
with open(template_path, "r", encoding="utf-8") as f:
|
|
176
|
+
template = f.read()
|
|
177
|
+
|
|
178
|
+
html_output = template.replace("{{MISSIONS_ROWS}}", "\n".join(missions_rows))
|
|
179
|
+
html_output = html_output.replace("{{VARIABLES_ROWS}}", "\n".join(variables_rows))
|
|
180
|
+
|
|
181
|
+
return html_output
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Dict, Type, Optional
|
|
2
|
+
|
|
3
|
+
from .deep_archimedea import DeepArchimedeaSource
|
|
4
|
+
from .temporal_archimedea import TemporalArchimedeaSource
|
|
5
|
+
from ..core.data_source import ResearchDataSource
|
|
6
|
+
from nonebot.log import logger
|
|
7
|
+
|
|
8
|
+
# 注册表:command_name -> 数据源类
|
|
9
|
+
_registry: Dict[str, Type[ResearchDataSource]] = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register_source(name: str, cls: Type[ResearchDataSource]) -> None:
|
|
13
|
+
"""
|
|
14
|
+
手动注册数据源类到注册中心
|
|
15
|
+
|
|
16
|
+
:param name: 命令名称(如 'time_research')
|
|
17
|
+
:param cls: 数据源类
|
|
18
|
+
"""
|
|
19
|
+
if name in _registry:
|
|
20
|
+
raise KeyError(f"命令 '{name}' 已被注册,请检查是否有重复")
|
|
21
|
+
_registry[name] = cls
|
|
22
|
+
logger.info(f"✅ 已注册数据源: {name} -> {cls.__name__}") # 或使用 logger
|
|
23
|
+
|
|
24
|
+
def get_source(cmd_name: str) -> ResearchDataSource:
|
|
25
|
+
"""根据命令名获取数据源实例"""
|
|
26
|
+
cls = _registry.get(cmd_name)
|
|
27
|
+
if not cls:
|
|
28
|
+
raise ValueError(f"未找到命令 '{cmd_name}' 对应的数据源")
|
|
29
|
+
return cls() # 每次调用返回新实例
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def list_sources() -> list[str]:
|
|
33
|
+
"""列出所有已注册的命令名"""
|
|
34
|
+
return list(_registry.keys())
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
register_source("temporal_archimedea", TemporalArchimedeaSource)
|
|
38
|
+
register_source("deep_archimedea",DeepArchimedeaSource)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# data_sources/conquest_base.py
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
from ..core.data_source import ResearchDataSource
|
|
5
|
+
from ..data_fetcher import fetch_world_state
|
|
6
|
+
from ..data_processor import transform_to_archimedea_data, extract_conquests
|
|
7
|
+
|
|
8
|
+
class ConquestDataSource(ResearchDataSource):
|
|
9
|
+
"""基于 Conquests 列表的数据源基类(专用于 World State 的 Conquest 类型)"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def conquest_type(self) -> str:
|
|
14
|
+
"""需要的 Conquest 类型,如 'CT_HEX' 或 'CT_LAB'"""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
async def fetch(self) -> Dict[str, Any]:
|
|
18
|
+
raw_data = await fetch_world_state()
|
|
19
|
+
conquests = extract_conquests(raw_data) # 抽取 Conquests 列表
|
|
20
|
+
target = next((c for c in conquests if c.get('Type') == self.conquest_type), None)
|
|
21
|
+
if not target:
|
|
22
|
+
return {"Missions": [], "Variables": []}
|
|
23
|
+
return transform_to_archimedea_data(target)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# renderers/__init__.py
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from .html_renderer import HtmlImageRenderer
|
|
5
|
+
from ..data_processor import render_archimedea_panel # 导入我们定义的函数
|
|
6
|
+
|
|
7
|
+
# 确定模板目录
|
|
8
|
+
TEMPLATE_DIR = Path(__file__).parent.parent / "assets" / "templates"
|
|
9
|
+
OUTPUT_DIR = Path(__file__).parent.parent / "images" # 用于缓存
|
|
10
|
+
|
|
11
|
+
# 创建全局渲染器实例
|
|
12
|
+
renderer = HtmlImageRenderer(
|
|
13
|
+
template_dir=TEMPLATE_DIR,
|
|
14
|
+
output_dir=OUTPUT_DIR,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# 注册 archimedea 模板,同时指定该模板专属的渲染参数
|
|
18
|
+
renderer.register_renderer(
|
|
19
|
+
template_type="archimedea",
|
|
20
|
+
func=render_archimedea_panel,
|
|
21
|
+
config={
|
|
22
|
+
"max_width": 1060, # archimedea 需要更宽
|
|
23
|
+
"allow_refit": False
|
|
24
|
+
}
|
|
25
|
+
)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# renderers/html_renderer.py
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Any, Callable, Optional, Union
|
|
5
|
+
from nonebot.log import logger
|
|
6
|
+
from nonebot_plugin_htmlkit import html_to_pic
|
|
7
|
+
|
|
8
|
+
# 定义渲染函数类型:接收数据字典和模板路径,返回HTML字符串
|
|
9
|
+
RenderFunc = Callable[[Dict[str, Any], str], str]
|
|
10
|
+
|
|
11
|
+
class HtmlImageRenderer:
|
|
12
|
+
"""
|
|
13
|
+
通用的HTML图片渲染器
|
|
14
|
+
支持注册多种数据→HTML的转换函数,自动适配不同模板
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
template_dir: Path,
|
|
20
|
+
output_dir: Optional[Path] = None,
|
|
21
|
+
):
|
|
22
|
+
self.template_dir = Path(template_dir).resolve()
|
|
23
|
+
self.output_dir = Path(output_dir).resolve() if output_dir else None
|
|
24
|
+
if self.output_dir:
|
|
25
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
# 注册表:template_type -> {"func": RenderFunc, "config": dict}
|
|
28
|
+
self._renderers: Dict[str, Dict[str, Any]] = {}
|
|
29
|
+
|
|
30
|
+
logger.info(f"HtmlImageRenderer initialized, template_dir: {self.template_dir}")
|
|
31
|
+
|
|
32
|
+
def register_renderer(self, template_type: str, func: RenderFunc, config: Optional[Dict] = None):
|
|
33
|
+
"""
|
|
34
|
+
注册一种数据渲染方式
|
|
35
|
+
:param template_type: 模板标识,如 "archimedea"
|
|
36
|
+
:param func: 接收 (data, template_path) 并返回 HTML 字符串的函数
|
|
37
|
+
:param config: 该模板专属的渲染参数(会覆盖默认参数),键与 html_to_pic 参数一致
|
|
38
|
+
"""
|
|
39
|
+
if template_type in self._renderers:
|
|
40
|
+
logger.warning(f"模板类型 '{template_type}' 已注册,将被覆盖")
|
|
41
|
+
self._renderers[template_type] = {
|
|
42
|
+
"func": func,
|
|
43
|
+
"config": config or {}
|
|
44
|
+
}
|
|
45
|
+
logger.info(f"Registered renderer for template type: {template_type} (config: {config})")
|
|
46
|
+
|
|
47
|
+
def get_renderer(self, template_type: str) -> Optional[RenderFunc]:
|
|
48
|
+
"""获取指定类型的渲染函数"""
|
|
49
|
+
entry = self._renderers.get(template_type)
|
|
50
|
+
return entry["func"] if entry else None
|
|
51
|
+
|
|
52
|
+
async def render(
|
|
53
|
+
self,
|
|
54
|
+
data: Dict[str, Any],
|
|
55
|
+
template_type: str,
|
|
56
|
+
template_filename: Optional[str] = None,
|
|
57
|
+
output_filename: Optional[str] = None,
|
|
58
|
+
**override_config,
|
|
59
|
+
) -> bytes:
|
|
60
|
+
"""
|
|
61
|
+
渲染数据为图片
|
|
62
|
+
:param data: 要渲染的数据(字典)
|
|
63
|
+
:param template_type: 模板类型(用于查找对应的渲染函数和配置)
|
|
64
|
+
:param template_filename: 模板文件名(若为None,则使用 template_type + '.html')
|
|
65
|
+
:param output_filename: 如果指定,则保存到文件
|
|
66
|
+
:param override_config: 覆盖渲染参数(最高优先级)
|
|
67
|
+
:return: 图片二进制数据
|
|
68
|
+
"""
|
|
69
|
+
# 1. 获取对应的渲染函数
|
|
70
|
+
entry = self._renderers.get(template_type)
|
|
71
|
+
if not entry:
|
|
72
|
+
raise ValueError(f"未注册的模板类型: {template_type}")
|
|
73
|
+
render_func = entry["func"]
|
|
74
|
+
|
|
75
|
+
# 2. 确定模板文件路径
|
|
76
|
+
if template_filename is None:
|
|
77
|
+
template_filename = f"{template_type}.html"
|
|
78
|
+
template_path = self.template_dir / template_filename
|
|
79
|
+
if not template_path.exists():
|
|
80
|
+
raise FileNotFoundError(f"模板文件不存在: {template_path}")
|
|
81
|
+
|
|
82
|
+
# 3. 调用渲染函数生成HTML
|
|
83
|
+
html = render_func(data, str(template_path))
|
|
84
|
+
logger.debug(f"Generated HTML for {template_type}, length: {len(html)}")
|
|
85
|
+
|
|
86
|
+
# 4. 合并渲染参数:默认配置 + 模板配置 + 调用覆盖
|
|
87
|
+
# 模板配置
|
|
88
|
+
template_config = entry.get("config", {})
|
|
89
|
+
# 调用覆盖
|
|
90
|
+
template_config.update(override_config)
|
|
91
|
+
|
|
92
|
+
logger.info(f"Config: {template_config}")
|
|
93
|
+
# 5. 转图片
|
|
94
|
+
try:
|
|
95
|
+
img_bytes = await html_to_pic(
|
|
96
|
+
html,
|
|
97
|
+
base_url=f"file://{self.template_dir}/",
|
|
98
|
+
**template_config, # 展开所有参数
|
|
99
|
+
)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
logger.error(f"HTML转图片失败: {e}")
|
|
102
|
+
raise
|
|
103
|
+
|
|
104
|
+
# 6. 可选保存
|
|
105
|
+
if self.output_dir and output_filename:
|
|
106
|
+
filepath = self.output_dir / output_filename
|
|
107
|
+
with open(filepath, "wb") as f:
|
|
108
|
+
f.write(img_bytes)
|
|
109
|
+
logger.info(f"图片已保存: {filepath}")
|
|
110
|
+
|
|
111
|
+
return img_bytes
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nonebot-plugin-aawarframe
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Default template for PDM package
|
|
5
|
+
Author-email: nekox41 <aameow@outlook.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: ==3.12.*
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: nonebot2>=2.5.0
|
|
11
|
+
Requires-Dist: httpx~=0.28.1
|
|
12
|
+
Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc5
|
|
13
|
+
Requires-Dist: nonebot-adapter-onebot>=2.4.6
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
<div align="center">
|
|
17
|
+
<a href="https://v2.nonebot.dev/store"><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.png" width="180" height="180" alt="aawarframeLogo"></a>
|
|
18
|
+
<br>
|
|
19
|
+
<p><img src="https://github.com/nekox41/nonebot-plugin-aawarframe/blob/master/logo.svg" width="240" alt="aawarframeLogo"></p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div align="center">
|
|
23
|
+
|
|
24
|
+
# nonebot-plugin-aawarframe
|
|
25
|
+
|
|
26
|
+
_✨ Aa 的 Warframe 助手,用于查询游戏状态。 ✨_
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<a href="./LICENSE">
|
|
30
|
+
<img src="https://img.shields.io/github/license/nekox41/nonebot-plugin-aawarframe.svg" alt="license">
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://pypi.python.org/pypi/nonebot-plugin-aawarframe">
|
|
33
|
+
<img src="https://img.shields.io/pypi/v/nonebot-plugin-aawarframe.svg" alt="pypi">
|
|
34
|
+
</a>
|
|
35
|
+
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
## 📖 介绍
|
|
40
|
+
|
|
41
|
+
这里是插件的详细介绍部分
|
|
42
|
+
|
|
43
|
+
## 💿 安装
|
|
44
|
+
|
|
45
|
+
<details open>
|
|
46
|
+
<summary>使用 nb-cli 安装</summary>
|
|
47
|
+
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
|
48
|
+
|
|
49
|
+
nb plugin install nonebot-plugin-aawarframe
|
|
50
|
+
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
<details>
|
|
54
|
+
<summary>使用包管理器安装</summary>
|
|
55
|
+
在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
|
|
56
|
+
|
|
57
|
+
<details>
|
|
58
|
+
<summary>pip</summary>
|
|
59
|
+
|
|
60
|
+
pip install nonebot-plugin-aawarframe
|
|
61
|
+
</details>
|
|
62
|
+
<details>
|
|
63
|
+
<summary>pdm</summary>
|
|
64
|
+
|
|
65
|
+
pdm add nonebot-plugin-aawarframe
|
|
66
|
+
</details>
|
|
67
|
+
<details>
|
|
68
|
+
<summary>poetry</summary>
|
|
69
|
+
|
|
70
|
+
poetry add nonebot-plugin-aawarframe
|
|
71
|
+
</details>
|
|
72
|
+
<details>
|
|
73
|
+
<summary>conda</summary>
|
|
74
|
+
|
|
75
|
+
conda install nonebot-plugin-aawarframe
|
|
76
|
+
</details>
|
|
77
|
+
|
|
78
|
+
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
|
|
79
|
+
|
|
80
|
+
plugins = ["nonebot_plugin_template"]
|
|
81
|
+
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
## ⚙️ 配置
|
|
85
|
+
|
|
86
|
+
在 nonebot2 项目的`.env`文件中添加下表中的必填配置
|
|
87
|
+
|
|
88
|
+
| 配置项 | 必填 | 默认值 | 说明 |
|
|
89
|
+
|:-----:|:----:|:----:|:----:|
|
|
90
|
+
| 配置项1 | 是 | 无 | 配置说明 |
|
|
91
|
+
| 配置项2 | 否 | 无 | 配置说明 |
|
|
92
|
+
|
|
93
|
+
## 🎉 使用
|
|
94
|
+
### 指令表
|
|
95
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
|
96
|
+
|:-----:|:----:|:----:|:----:|:----:|
|
|
97
|
+
| 指令1 | 主人 | 否 | 私聊 | 指令说明 |
|
|
98
|
+
| 指令2 | 群员 | 是 | 群聊 | 指令说明 |
|
|
99
|
+
### 效果图
|
|
100
|
+
如果有效果图的话
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
nonebot_plugin_aawarframe/__init__.py
|
|
5
|
+
nonebot_plugin_aawarframe/data_fetcher.py
|
|
6
|
+
nonebot_plugin_aawarframe/data_processor.py
|
|
7
|
+
nonebot_plugin_aawarframe.egg-info/PKG-INFO
|
|
8
|
+
nonebot_plugin_aawarframe.egg-info/SOURCES.txt
|
|
9
|
+
nonebot_plugin_aawarframe.egg-info/dependency_links.txt
|
|
10
|
+
nonebot_plugin_aawarframe.egg-info/requires.txt
|
|
11
|
+
nonebot_plugin_aawarframe.egg-info/top_level.txt
|
|
12
|
+
nonebot_plugin_aawarframe/core/data_source.py
|
|
13
|
+
nonebot_plugin_aawarframe/data_sources/__init__.py
|
|
14
|
+
nonebot_plugin_aawarframe/data_sources/conquest_base.py
|
|
15
|
+
nonebot_plugin_aawarframe/data_sources/deep_archimedea.py
|
|
16
|
+
nonebot_plugin_aawarframe/data_sources/temporal_archimedea.py
|
|
17
|
+
nonebot_plugin_aawarframe/renderers/__init__.py
|
|
18
|
+
nonebot_plugin_aawarframe/renderers/html_renderer.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nonebot_plugin_aawarframe
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nonebot-plugin-aawarframe"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Default template for PDM package"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "nekox41",email = "aameow@outlook.com"},
|
|
7
|
+
]
|
|
8
|
+
dependencies = ["nonebot2>=2.5.0", "httpx~=0.28.1", "nonebot-plugin-htmlkit>=0.1.0rc5", "nonebot-adapter-onebot>=2.4.6"]
|
|
9
|
+
requires-python = "==3.12.*"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
[tool.pdm]
|
|
15
|
+
distribution = false
|