nonebot-plugin-ba-gamekee 0.2.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.
Files changed (19) hide show
  1. nonebot_plugin_ba_gamekee-0.2.0/PKG-INFO +134 -0
  2. nonebot_plugin_ba_gamekee-0.2.0/README.md +115 -0
  3. nonebot_plugin_ba_gamekee-0.2.0/pyproject.toml +131 -0
  4. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/__init__.py +57 -0
  5. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/bot/__init__.py +3 -0
  6. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/bot/article_delivery.py +70 -0
  7. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/bot/dependencies.py +134 -0
  8. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/bot/handlers/__init__.py +3 -0
  9. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/bot/handlers/guides.py +173 -0
  10. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/config.py +13 -0
  11. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/core/__init__.py +17 -0
  12. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/core/guide_kinds.py +92 -0
  13. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/core/models.py +61 -0
  14. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/core/servers.py +47 -0
  15. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/infra/__init__.py +3 -0
  16. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/infra/article_renderer.py +678 -0
  17. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/infra/current_guides_cache.py +56 -0
  18. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/infra/gamekee.py +199 -0
  19. nonebot_plugin_ba_gamekee-0.2.0/src/nonebot_plugin_ba_gamekee/infra/screenshot_cache.py +215 -0
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.3
2
+ Name: nonebot-plugin-ba-gamekee
3
+ Version: 0.2.0
4
+ Summary: 蔚蓝档案 GameKee Wiki 攻略查询
5
+ Author: Misty02600
6
+ Author-email: Misty02600 <xiao02600@gmail.com>
7
+ Requires-Dist: httpx>=0.27.0,<1.0.0
8
+ Requires-Dist: nonebot-plugin-alconna>=0.60.0,<1.0.0
9
+ Requires-Dist: nonebot-plugin-apscheduler>=0.5.0,<1.0.0
10
+ Requires-Dist: nonebot-plugin-localstore>=0.7.4,<1.0.0
11
+ Requires-Dist: nonebot-plugin-uninfo>=0.10.0,<1.0.0
12
+ Requires-Dist: nonebot2>=2.4.2,<3.0.0
13
+ Requires-Dist: playwright>=1.58.0,<2.0.0
14
+ Requires-Python: >=3.11
15
+ Project-URL: Homepage, https://github.com/Misty02600/nonebot-plugin-ba-gamekee
16
+ Project-URL: Issues, https://github.com/Misty02600/nonebot-plugin-ba-gamekee/issues
17
+ Project-URL: Repository, https://github.com/Misty02600/nonebot-plugin-ba-gamekee.git
18
+ Description-Content-Type: text/markdown
19
+
20
+ <div align="center">
21
+ <a href="https://v2.nonebot.dev/store">
22
+ <img src="https://github.com/Misty02600/nonebot-plugin-template/releases/download/assets/NoneBotPlugin.png" width="310" alt="logo"></a>
23
+
24
+ ## ✨ nonebot-plugin-ba-gamekee ✨
25
+ [![LICENSE](https://img.shields.io/github/license/Misty02600/nonebot-plugin-ba-gamekee.svg)](./LICENSE)
26
+ [![python](https://img.shields.io/badge/python-3.11+-blue.svg?logo=python&logoColor=white)](https://www.python.org)
27
+ [![Adapters](https://img.shields.io/badge/Adapters-OneBot%20v11-blue)](#supported-adapters)
28
+ <br/>
29
+
30
+ [![uv](https://img.shields.io/badge/package%20manager-uv-black?logo=uv)](https://github.com/astral-sh/uv)
31
+ [![ruff](https://img.shields.io/badge/code%20style-ruff-black?logo=ruff)](https://github.com/astral-sh/ruff)
32
+
33
+ </div>
34
+
35
+ ## 📖 介绍
36
+
37
+ `nonebot-plugin-ba-gamekee` 是面向 Blue Archive / 蔚蓝档案的 GameKee Wiki 攻略查询插件。
38
+
39
+ 当前已支持查询三服当前活动攻略与卡池评测入口,并会在后台同步 GameKee 首页入口缓存,减少实时请求压力。
40
+
41
+ ## 💿 安装
42
+
43
+ <details open>
44
+ <summary>使用 nb-cli 安装</summary>
45
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
46
+
47
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade
48
+ 使用 **pypi** 源安装
49
+
50
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade -i "https://pypi.org/simple"
51
+ 使用**清华源**安装
52
+
53
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade -i "https://pypi.tuna.tsinghua.edu.cn/simple"
54
+
55
+
56
+ </details>
57
+
58
+ <details>
59
+ <summary>使用包管理器安装</summary>
60
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
61
+
62
+ <details open>
63
+ <summary>uv</summary>
64
+
65
+ uv add nonebot-plugin-ba-gamekee
66
+ 安装仓库 main 分支
67
+
68
+ uv add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
69
+ </details>
70
+
71
+ <details>
72
+ <summary>pdm</summary>
73
+
74
+ pdm add nonebot-plugin-ba-gamekee
75
+ 安装仓库 main 分支
76
+
77
+ pdm add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
78
+ </details>
79
+ <details>
80
+ <summary>poetry</summary>
81
+
82
+ poetry add nonebot-plugin-ba-gamekee
83
+ 安装仓库 main 分支
84
+
85
+ poetry add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
86
+ </details>
87
+
88
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
89
+
90
+ plugins = ["nonebot_plugin_ba_gamekee"]
91
+
92
+ </details>
93
+
94
+ <details>
95
+ <summary>使用 nbr 安装(使用 uv 管理依赖可用)</summary>
96
+
97
+ [nbr](https://github.com/fllesser/nbr) 是一个基于 uv 的 nb-cli,可以方便地管理 nonebot2
98
+
99
+ nbr plugin install nonebot-plugin-ba-gamekee
100
+ 使用 **pypi** 源安装
101
+
102
+ nbr plugin install nonebot-plugin-ba-gamekee -i "https://pypi.org/simple"
103
+ 使用**清华源**安装
104
+
105
+ nbr plugin install nonebot-plugin-ba-gamekee -i "https://pypi.tuna.tsinghua.edu.cn/simple"
106
+
107
+ </details>
108
+
109
+
110
+ ## ⚙️ 配置
111
+
112
+ 插件使用 [nonebot_plugin_localstore](https://github.com/nonebot/plugin-localstore) 储存数据和缓存,并使用 apscheduler 定时刷新 GameKee 首页入口。
113
+
114
+ 可在 nonebot2 项目的 `.env` 文件中按需覆盖下表配置。
115
+
116
+ | 配置项 | 必填 | 默认值 | 说明 |
117
+ | :-----: | :---: | :----: | :------: |
118
+ | `ba_gamekee_refresh_interval_minutes` | 否 | `10` | 后台刷新当前攻略入口缓存的间隔,单位为分钟 |
119
+
120
+ ## 🎉 使用
121
+ ### 指令表
122
+ | 指令 | 权限 | 需要@ | 范围 | 说明 |
123
+ | :---: | :---: | :---: | :---: | :------: |
124
+ | `/ba活动 日服` | 群员 | 否 | 私聊/群聊 | 查询当前日服活动攻略 |
125
+ | `/ba活动 国际服` | 群员 | 否 | 私聊/群聊 | 查询当前国际服活动攻略 |
126
+ | `/ba活动 国服` | 群员 | 否 | 私聊/群聊 | 查询当前国服活动攻略 |
127
+ | `/ba卡池 日服` | 群员 | 否 | 私聊/群聊 | 查询当前日服卡池评测 |
128
+ | `/ba卡池 国际服` | 群员 | 否 | 私聊/群聊 | 查询当前国际服卡池评测 |
129
+ | `/ba卡池 国服` | 群员 | 否 | 私聊/群聊 | 查询当前国服卡池评测 |
130
+
131
+ `ba` 与子命令之间可以加空格,例如 `/ba 活动 国际服`、`/ba 卡池 国服`。子命令与服务器参数之间需要分隔。
132
+
133
+ ### 🎨 效果图
134
+ 如果有效果图的话
@@ -0,0 +1,115 @@
1
+ <div align="center">
2
+ <a href="https://v2.nonebot.dev/store">
3
+ <img src="https://github.com/Misty02600/nonebot-plugin-template/releases/download/assets/NoneBotPlugin.png" width="310" alt="logo"></a>
4
+
5
+ ## ✨ nonebot-plugin-ba-gamekee ✨
6
+ [![LICENSE](https://img.shields.io/github/license/Misty02600/nonebot-plugin-ba-gamekee.svg)](./LICENSE)
7
+ [![python](https://img.shields.io/badge/python-3.11+-blue.svg?logo=python&logoColor=white)](https://www.python.org)
8
+ [![Adapters](https://img.shields.io/badge/Adapters-OneBot%20v11-blue)](#supported-adapters)
9
+ <br/>
10
+
11
+ [![uv](https://img.shields.io/badge/package%20manager-uv-black?logo=uv)](https://github.com/astral-sh/uv)
12
+ [![ruff](https://img.shields.io/badge/code%20style-ruff-black?logo=ruff)](https://github.com/astral-sh/ruff)
13
+
14
+ </div>
15
+
16
+ ## 📖 介绍
17
+
18
+ `nonebot-plugin-ba-gamekee` 是面向 Blue Archive / 蔚蓝档案的 GameKee Wiki 攻略查询插件。
19
+
20
+ 当前已支持查询三服当前活动攻略与卡池评测入口,并会在后台同步 GameKee 首页入口缓存,减少实时请求压力。
21
+
22
+ ## 💿 安装
23
+
24
+ <details open>
25
+ <summary>使用 nb-cli 安装</summary>
26
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
27
+
28
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade
29
+ 使用 **pypi** 源安装
30
+
31
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade -i "https://pypi.org/simple"
32
+ 使用**清华源**安装
33
+
34
+ nb plugin install nonebot-plugin-ba-gamekee --upgrade -i "https://pypi.tuna.tsinghua.edu.cn/simple"
35
+
36
+
37
+ </details>
38
+
39
+ <details>
40
+ <summary>使用包管理器安装</summary>
41
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
42
+
43
+ <details open>
44
+ <summary>uv</summary>
45
+
46
+ uv add nonebot-plugin-ba-gamekee
47
+ 安装仓库 main 分支
48
+
49
+ uv add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
50
+ </details>
51
+
52
+ <details>
53
+ <summary>pdm</summary>
54
+
55
+ pdm add nonebot-plugin-ba-gamekee
56
+ 安装仓库 main 分支
57
+
58
+ pdm add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
59
+ </details>
60
+ <details>
61
+ <summary>poetry</summary>
62
+
63
+ poetry add nonebot-plugin-ba-gamekee
64
+ 安装仓库 main 分支
65
+
66
+ poetry add git+https://github.com/Misty02600/nonebot-plugin-ba-gamekee@main
67
+ </details>
68
+
69
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
70
+
71
+ plugins = ["nonebot_plugin_ba_gamekee"]
72
+
73
+ </details>
74
+
75
+ <details>
76
+ <summary>使用 nbr 安装(使用 uv 管理依赖可用)</summary>
77
+
78
+ [nbr](https://github.com/fllesser/nbr) 是一个基于 uv 的 nb-cli,可以方便地管理 nonebot2
79
+
80
+ nbr plugin install nonebot-plugin-ba-gamekee
81
+ 使用 **pypi** 源安装
82
+
83
+ nbr plugin install nonebot-plugin-ba-gamekee -i "https://pypi.org/simple"
84
+ 使用**清华源**安装
85
+
86
+ nbr plugin install nonebot-plugin-ba-gamekee -i "https://pypi.tuna.tsinghua.edu.cn/simple"
87
+
88
+ </details>
89
+
90
+
91
+ ## ⚙️ 配置
92
+
93
+ 插件使用 [nonebot_plugin_localstore](https://github.com/nonebot/plugin-localstore) 储存数据和缓存,并使用 apscheduler 定时刷新 GameKee 首页入口。
94
+
95
+ 可在 nonebot2 项目的 `.env` 文件中按需覆盖下表配置。
96
+
97
+ | 配置项 | 必填 | 默认值 | 说明 |
98
+ | :-----: | :---: | :----: | :------: |
99
+ | `ba_gamekee_refresh_interval_minutes` | 否 | `10` | 后台刷新当前攻略入口缓存的间隔,单位为分钟 |
100
+
101
+ ## 🎉 使用
102
+ ### 指令表
103
+ | 指令 | 权限 | 需要@ | 范围 | 说明 |
104
+ | :---: | :---: | :---: | :---: | :------: |
105
+ | `/ba活动 日服` | 群员 | 否 | 私聊/群聊 | 查询当前日服活动攻略 |
106
+ | `/ba活动 国际服` | 群员 | 否 | 私聊/群聊 | 查询当前国际服活动攻略 |
107
+ | `/ba活动 国服` | 群员 | 否 | 私聊/群聊 | 查询当前国服活动攻略 |
108
+ | `/ba卡池 日服` | 群员 | 否 | 私聊/群聊 | 查询当前日服卡池评测 |
109
+ | `/ba卡池 国际服` | 群员 | 否 | 私聊/群聊 | 查询当前国际服卡池评测 |
110
+ | `/ba卡池 国服` | 群员 | 否 | 私聊/群聊 | 查询当前国服卡池评测 |
111
+
112
+ `ba` 与子命令之间可以加空格,例如 `/ba 活动 国际服`、`/ba 卡池 国服`。子命令与服务器参数之间需要分隔。
113
+
114
+ ### 🎨 效果图
115
+ 如果有效果图的话
@@ -0,0 +1,131 @@
1
+ [project]
2
+ name = "nonebot-plugin-ba-gamekee"
3
+ version = "0.2.0"
4
+ description = "蔚蓝档案 GameKee Wiki 攻略查询"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ authors = [{ name = "Misty02600", email = "xiao02600@gmail.com" }]
8
+ dependencies = [
9
+ "httpx>=0.27.0,<1.0.0",
10
+ "nonebot-plugin-alconna>=0.60.0,<1.0.0",
11
+ "nonebot-plugin-apscheduler>=0.5.0,<1.0.0",
12
+ "nonebot-plugin-localstore>=0.7.4,<1.0.0",
13
+ "nonebot-plugin-uninfo>=0.10.0,<1.0.0",
14
+ "nonebot2>=2.4.2,<3.0.0",
15
+ "playwright>=1.58.0,<2.0.0",
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/Misty02600/nonebot-plugin-ba-gamekee"
20
+ Issues = "https://github.com/Misty02600/nonebot-plugin-ba-gamekee/issues"
21
+ Repository = "https://github.com/Misty02600/nonebot-plugin-ba-gamekee.git"
22
+
23
+ [dependency-groups]
24
+ dev = [
25
+ "commitizen>=4.1.0",
26
+ "git-cliff>=2.11.0,<3.0.0",
27
+ "prek>=0.2.0",
28
+ { include-group = "test" },
29
+ ]
30
+ test = [
31
+ "basedpyright>=1.16.0",
32
+ "ruff>=0.14.13,<1.0.0",
33
+ "nonebot-adapter-onebot>=2.4.6,<3.0.0",
34
+ "nonebot2[fastapi]>=2.4.4,<3.0.0",
35
+ "nonebug>=0.4.3,<1.0.0",
36
+ "pytest-asyncio>=1.3.0,<1.4.0",
37
+ "pytest-cov>=7.0.0",
38
+ ]
39
+
40
+ [tool.nonebot.plugins]
41
+ nonebot-plugin-ba-gamekee = ["nonebot_plugin_ba_gamekee"]
42
+
43
+ [tool.nonebot.adapters]
44
+ nonebot-adapter-onebot = [
45
+ { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
46
+ ]
47
+
48
+ [build-system]
49
+ requires = ["uv_build>=0.10.0,<0.11.0"]
50
+ build-backend = "uv_build"
51
+
52
+ [tool.commitizen]
53
+ name = "cz_conventional_commits"
54
+ version = "0.1.0"
55
+ version_provider = "uv"
56
+ tag_format = "v$version"
57
+ annotated_tag = true
58
+ major_version_zero = true # 允许 0.x.x 版本号
59
+
60
+ [tool.coverage.report]
61
+ exclude_lines = [
62
+ "raise NotImplementedError",
63
+ "if TYPE_CHECKING:",
64
+ "@overload",
65
+ "except ImportError:",
66
+ ]
67
+
68
+ [tool.pyright]
69
+ include = ["src"] # 默认仅检查源码目录;测试通过 pytest / ruff 保证质量
70
+ pythonVersion = "3.11" # 目标 Python 版本(影响可用的类型特性)
71
+ pythonPlatform = "All" # 目标平台:All | Linux | Windows | Darwin
72
+ # typeCheckingMode 类型检查严格程度,可选值:
73
+ # - "off": 关闭类型检查
74
+ # - "basic": 基础检查(仅报告明确的类型错误)
75
+ # - "standard": 标准检查(推荐,平衡严格性与实用性)
76
+ # - "strict": 严格检查(要求完整的类型注解,适合新项目)
77
+ # - "all": 最严格(启用所有检查,可能产生大量警告)
78
+ typeCheckingMode = "standard"
79
+
80
+ [tool.pytest.ini_options]
81
+ addopts = [
82
+ "--import-mode=importlib", # 使用 importlib 导入模式(推荐,避免 sys.path 污染)
83
+ "--strict-markers", # 严格标记模式(未注册的 marker 会报错)
84
+ "--tb=short", # 简短的错误回溯(减少输出噪音)
85
+ "-ra", # 显示所有非通过测试的摘要(a=all except passed)
86
+ ]
87
+ pythonpath = ["src", "tests"] # 添加到 Python 路径,确保模块可导入
88
+ asyncio_mode = "auto" # 自动检测异步测试函数,无需手动标记 @pytest.mark.asyncio
89
+
90
+ [tool.ruff]
91
+ line-length = 88 # 每行最大字符数(与 Black 保持一致)
92
+ src = ["src", "tests"] # 源代码目录(用于判断导入是本地模块还是第三方模块)
93
+ extend-exclude = ["scripts"] # 脚本目录不做 lint 检查
94
+
95
+ [tool.ruff.format]
96
+ line-ending = "lf" # 行尾符:lf(Unix)| crlf(Windows)| auto | native
97
+
98
+ [tool.ruff.lint]
99
+ # 启用的规则集,每个字母代码对应一组规则
100
+ select = [
101
+ "F", # Pyflakes:基础语法和逻辑错误检查
102
+ "W", # pycodestyle warnings:PEP 8 风格警告
103
+ "E", # pycodestyle errors:PEP 8 风格错误
104
+ "I", # isort:导入语句排序
105
+ "B", # flake8-bugbear:发现潜在 bug 和设计问题
106
+ "UP", # pyupgrade:升级到新版 Python 语法
107
+ "ASYNC", # flake8-async:异步代码最佳实践
108
+ "C4", # flake8-comprehensions:推导式优化建议
109
+ "T10", # flake8-debugger:检测遗留的调试器语句(如 pdb)
110
+ "T20", # flake8-print:检测 print 语句(生产代码应使用 logging)
111
+ "PYI", # flake8-pyi:类型存根文件(.pyi)规范检查
112
+ "PT", # flake8-pytest-style:pytest 代码风格检查
113
+ "Q", # flake8-quotes:引号使用规范
114
+ "TID", # flake8-tidy-imports:导入语句整理
115
+ "RUF", # Ruff-specific:Ruff 特有的规则
116
+ ]
117
+ # 忽略的规则(根据项目需求放宽)
118
+ ignore = [
119
+ "E501", # 行长度由 formatter 控制,lint 不重复检查
120
+ "E402", # 允许模块导入不在文件顶部(某些情况下需要先执行代码)
121
+ "UP037", # 允许使用引号包裹的类型注解(前向引用)
122
+ "RUF001", # 允许字符串中的中文等 Unicode 字符
123
+ "RUF002", # 允许文档字符串中的中文等 Unicode 字符
124
+ "RUF003", # 允许注释中的中文等 Unicode 字符
125
+ "W191", # 允许使用制表符缩进
126
+ "TID252", # 允许使用相对导入
127
+ "B008", # 允许在函数参数默认值中使用函数调用
128
+ ]
129
+
130
+ [tool.ruff.lint.isort]
131
+ extra-standard-library = ["typing_extensions"] # 将 typing_extensions 视为标准库
@@ -0,0 +1,57 @@
1
+ from nonebot import get_driver, require
2
+ from nonebot.plugin import PluginMetadata, inherit_supported_adapters
3
+
4
+ require("nonebot_plugin_alconna")
5
+ require("nonebot_plugin_uninfo")
6
+ require("nonebot_plugin_localstore")
7
+ require("nonebot_plugin_apscheduler")
8
+
9
+ from nonebot_plugin_apscheduler import scheduler
10
+
11
+ from . import bot as bot
12
+ from .bot.dependencies import (
13
+ get_current_guide_cache,
14
+ get_current_guide_client,
15
+ refresh_current_guides,
16
+ startup_current_guides,
17
+ )
18
+ from .config import Config, plugin_config
19
+
20
+ __plugin_meta__ = PluginMetadata(
21
+ name="BA GameKee",
22
+ description="蔚蓝档案 GameKee Wiki 攻略查询",
23
+ usage="/ba活动 国际服\n/ba卡池 国服",
24
+ type="application", # application: 功能性插件 | library: 库插件
25
+ homepage="https://github.com/Misty02600/nonebot-plugin-ba-gamekee",
26
+ config=Config,
27
+ supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"),
28
+ extra={"author": "Misty02600 <xiao02600@gmail.com>"},
29
+ )
30
+
31
+
32
+ driver = get_driver()
33
+
34
+
35
+ @driver.on_startup
36
+ async def _sync_current_guides_on_startup() -> None:
37
+ await startup_current_guides(
38
+ client=get_current_guide_client(),
39
+ cache=get_current_guide_cache(),
40
+ )
41
+
42
+
43
+ async def _refresh_current_guides_job() -> None:
44
+ await refresh_current_guides(
45
+ client=get_current_guide_client(),
46
+ cache=get_current_guide_cache(),
47
+ silent=True,
48
+ )
49
+
50
+
51
+ scheduler.add_job(
52
+ _refresh_current_guides_job,
53
+ "interval",
54
+ minutes=plugin_config.ba_gamekee_refresh_interval_minutes,
55
+ id="ba_gamekee_refresh_current_guides",
56
+ replace_existing=True,
57
+ )
@@ -0,0 +1,3 @@
1
+ from .handlers.guides import ba_gamekee_matcher
2
+
3
+ __all__ = ["ba_gamekee_matcher"]
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Sequence
4
+ from pathlib import Path
5
+
6
+ from nonebot.adapters import Bot, Event
7
+ from nonebot_plugin_alconna import CustomNode, UniMessage
8
+ from nonebot_plugin_uninfo import get_interface
9
+
10
+ DEFAULT_FORWARD_SENDER_NAME = "BA GameKee"
11
+
12
+
13
+ async def send_article_pages(
14
+ *,
15
+ bot: Bot,
16
+ event: Event,
17
+ page_paths: Sequence[Path],
18
+ ) -> None:
19
+ """按平台能力发送文章分页图片。
20
+
21
+ Args:
22
+ bot: 当前响应 bot。
23
+ event: 当前事件。
24
+ page_paths: 已渲染完成的分页图片路径。
25
+ """
26
+ if not page_paths:
27
+ raise ValueError("article pages is empty")
28
+
29
+ if len(page_paths) == 1:
30
+ await UniMessage.image(path=page_paths[0], name=page_paths[0].name).send(
31
+ target=event,
32
+ bot=bot,
33
+ fallback=False,
34
+ )
35
+ return
36
+
37
+ await _send_forward_message(bot=bot, event=event, page_paths=page_paths)
38
+
39
+
40
+ async def _send_forward_message(
41
+ *,
42
+ bot: Bot,
43
+ event: Event,
44
+ page_paths: Sequence[Path],
45
+ ) -> None:
46
+ sender_name = await _resolve_forward_sender_name(bot)
47
+ nodes = [
48
+ CustomNode(
49
+ uid=str(bot.self_id),
50
+ name=sender_name,
51
+ content=UniMessage.image(path=path, name=path.name),
52
+ )
53
+ for path in page_paths
54
+ ]
55
+ await UniMessage.reference(*nodes).send(target=event, bot=bot)
56
+
57
+
58
+ async def _resolve_forward_sender_name(bot: Bot) -> str:
59
+ interface = get_interface(bot)
60
+ if interface is None:
61
+ return DEFAULT_FORWARD_SENDER_NAME
62
+
63
+ try:
64
+ user = await interface.get_user(str(bot.self_id))
65
+ except Exception:
66
+ return DEFAULT_FORWARD_SENDER_NAME
67
+
68
+ if user is None or not user.name:
69
+ return DEFAULT_FORWARD_SENDER_NAME
70
+ return user.name
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ from nonebot import logger
4
+
5
+ from ..core.models import GuideEntry
6
+ from ..infra.article_renderer import ArticleRenderer
7
+ from ..infra.current_guides_cache import CurrentGuideCache
8
+ from ..infra.gamekee import GameKeeClient
9
+ from ..infra.screenshot_cache import ScreenshotCache
10
+
11
+ _current_guide_client = GameKeeClient()
12
+ _current_guide_cache = CurrentGuideCache()
13
+ _article_renderer = ArticleRenderer()
14
+ _screenshot_cache = ScreenshotCache()
15
+ _current_guide_entries: dict[str, GuideEntry] = {}
16
+
17
+
18
+ def get_current_guide_client() -> GameKeeClient:
19
+ """获取共享的当前攻略入口数据源。
20
+
21
+ Returns:
22
+ GameKee 当前攻略入口客户端。
23
+ """
24
+ return _current_guide_client
25
+
26
+
27
+ def get_current_guide_cache() -> CurrentGuideCache:
28
+ """获取共享的当前攻略入口缓存。
29
+
30
+ Returns:
31
+ 当前攻略入口缓存实例。
32
+ """
33
+ return _current_guide_cache
34
+
35
+
36
+ def get_current_guide_entries() -> dict[str, GuideEntry]:
37
+ """获取当前攻略入口内存快照。
38
+
39
+ Returns:
40
+ 当前攻略入口内存快照。
41
+ """
42
+ return _current_guide_entries
43
+
44
+
45
+ def get_article_renderer() -> ArticleRenderer:
46
+ """获取共享的文章渲染器。
47
+
48
+ Returns:
49
+ 完整文章截图渲染器。
50
+ """
51
+ return _article_renderer
52
+
53
+
54
+ def get_screenshot_cache() -> ScreenshotCache:
55
+ """获取共享的文章截图缓存。
56
+
57
+ Returns:
58
+ 完整文章截图缓存实例。
59
+ """
60
+ return _screenshot_cache
61
+
62
+
63
+ def load_current_guides_cache(*, cache: CurrentGuideCache) -> dict[str, GuideEntry]:
64
+ """从本地缓存加载最近一次成功同步的攻略入口快照。
65
+
66
+ Args:
67
+ cache: 当前攻略入口缓存。
68
+
69
+ Returns:
70
+ 当前攻略入口内存快照。
71
+ """
72
+ global _current_guide_entries
73
+ _current_guide_entries = cache.load()
74
+ return _current_guide_entries
75
+
76
+
77
+ async def refresh_current_guides(
78
+ *,
79
+ client: GameKeeClient,
80
+ cache: CurrentGuideCache,
81
+ silent: bool = False,
82
+ ) -> dict[str, GuideEntry]:
83
+ """从 GameKee 刷新内存中的攻略入口快照。
84
+
85
+ Args:
86
+ client: 当前攻略入口数据源。
87
+ cache: 当前攻略入口缓存。
88
+ silent: 为 `True` 时,刷新失败会保留旧缓存并记录 warning,
89
+ 而不是继续抛出异常。
90
+
91
+ Returns:
92
+ 当前攻略入口内存快照。
93
+ """
94
+ global _current_guide_entries
95
+ try:
96
+ entries = await client.fetch_current_guide_entries()
97
+ if not entries:
98
+ raise RuntimeError("GameKee 当前入口为空")
99
+ _current_guide_entries = entries
100
+ cache.save(_current_guide_entries)
101
+ logger.info(f"BA GameKee 当前入口已同步:{len(entries)} 条")
102
+ except Exception as e:
103
+ if silent:
104
+ logger.warning(f"同步 BA GameKee 当前入口失败,将使用旧缓存:{e}")
105
+ return _current_guide_entries
106
+ raise
107
+ return _current_guide_entries
108
+
109
+
110
+ async def startup_current_guides(
111
+ *,
112
+ client: GameKeeClient,
113
+ cache: CurrentGuideCache,
114
+ ) -> None:
115
+ """启动时先加载本地缓存,再尝试静默刷新远端数据。
116
+
117
+ Args:
118
+ client: 当前攻略入口数据源。
119
+ cache: 当前攻略入口缓存。
120
+ """
121
+ load_current_guides_cache(cache=cache)
122
+ await refresh_current_guides(client=client, cache=cache, silent=True)
123
+
124
+
125
+ __all__ = [
126
+ "get_article_renderer",
127
+ "get_current_guide_cache",
128
+ "get_current_guide_client",
129
+ "get_current_guide_entries",
130
+ "get_screenshot_cache",
131
+ "load_current_guides_cache",
132
+ "refresh_current_guides",
133
+ "startup_current_guides",
134
+ ]
@@ -0,0 +1,3 @@
1
+ from .guides import ba_gamekee_matcher
2
+
3
+ __all__ = ["ba_gamekee_matcher"]