150 Commits

Author SHA1 Message Date
suyiiyii 40f4490b74 🔀 merge main 2024-10-31 00:50:20 +08:00
suyiiyii a1843bb98a 🐛 优化 SiteMeta 2024-10-30 23:43:18 +08:00
suyiiyii f08ab9f926 📝 fixs
📝 删除开发文档中过多的人称代词
2024-10-30 23:24:13 +08:00
suyiiyii fd349eefed ♻️ 复原 RegistryMeta 的位置 2024-10-30 20:18:28 +08:00
suyiiyii e8f0d578e1 ♻️ 将 Site 的元类从 RegistryMeta 改为 新建的 SiteMeta 2024-10-30 20:03:48 +08:00
suyiiyii 60dd2c4bab 📝 同步更新文档 2024-10-29 23:22:27 +08:00
suyiiyii d6b8d3b44e ✏️ small fixs 2024-10-29 23:13:26 +08:00
suyiiyii 3f7a9bf8a3 🔀 Merge remote-tracking branch 'upstream/main' into cookie 2024-10-29 22:56:10 +08:00
suyiiyii 955a06d9e9 🐛 修复低版本 python 不支持 override 2024-10-29 22:19:03 +08:00
suyiiyii 074fe3ff58 ♻️ _site_name 和 _default_cookie_cd 内置 CookieClientManager 2024-10-29 21:28:35 +08:00
suyiiyii 8a8a48aef6 ♻️ 移除CookieSite 2024-10-29 21:17:07 +08:00
suyiiyii c5dea7e252 ♻️ 初步移除CookieSite 2024-10-29 21:12:50 +08:00
suyiiyii 07190a7f64 ♻️ 改回 _site_name 2024-10-29 20:53:23 +08:00
suyiiyii 62386931d7 ♻️ 移除 bilibili 的 _site_name 属性 2024-10-29 14:43:16 +08:00
suyiiyii 32c237015f ♻️ 更新部分方法使用 scheduler_dict 进行cookie操作 2024-10-29 14:15:15 +08:00
suyiiyii 29c2eb456d ♻️ 更新部分方法使用 scheduler_dict 进行cookie操作 2024-10-29 12:24:31 +08:00
suyiiyii 9d985eb3c8 ♻️ bilibili 移除 _client 属性 2024-10-29 12:23:50 +08:00
suyiiyii 4805d0d77c ♻️ 在 CookieClientManager 中添加对对应的 Site 的引用 2024-10-29 11:33:28 +08:00
suyiiyii 81e53419a3 ♻️ 将 refresh_anonymous_cookie 改为内部方法, 同时外部使用 refresh_client 方法进行刷新匿名 cookie 2024-10-29 09:38:08 +08:00
suyiiyii b130627d7e ♻️ 还原对 bilibili platform 的修改 2024-10-29 00:48:35 +08:00
suyiiyii 4dd4555fc7 📝 更新文档 2024-10-29 00:44:58 +08:00
suyiiyii e6c45e5b1b ♻️ 为 row2dict 添加类型注解 2024-10-28 23:56:10 +08:00
suyiiyii b60ba566de ♻️ 将 default_cd 重命名为 default_cookie_cd 2024-10-28 23:54:12 +08:00
suyiiyii ac794efd18 :refactor: 将 cookie default_cd 移动到 CookieSite 内部 2024-10-28 23:50:04 +08:00
suyiiyii cdd671b15f 🐛 修复「管理后台」重复发送消息 2024-10-28 23:06:54 +08:00
suyiiyii 6e53c6f4b2 🐛 优化对 bilibili cookie 的 mock 2024-10-28 22:48:11 +08:00
suyiiyii 3a0f95b712 🐛 优化对 weibo get_cookie_name 的 mock 2024-10-28 22:47:31 +08:00
suyiiyii 641cc44a12 🔀 merge 2024-10-28 22:07:20 +08:00
suyiiyii 42cc56ac24 🐛 优化对 bilibili cookie 的 mock 2024-10-28 22:06:12 +08:00
suyiiyii 0deb406692 🐛 更新判断superuser的私聊消息的逻辑 2024-10-28 22:00:15 +08:00
suyiiyii eb64eab14a 添加cookie命令的无权限提示 2024-10-28 13:46:22 +08:00
suyiiyii 3043817de4 🐛 为cookie相关操作添加非私聊拒绝提示 2024-10-28 13:29:10 +08:00
suyiiyii 0985705c22 🐛 添加 Cookie 时,显示 「无法获取cookie_name」 的错误提示 2024-10-28 13:17:36 +08:00
suyiiyii 438b23a0b9 🐛 从 Site 中移除 「无效的 Cookie」 文本 2024-10-28 12:44:51 +08:00
suyiiyii dcd32f0662 📝 更新文档顶栏 2024-10-28 12:37:17 +08:00
suyiiyii 60cee1bcc1 🐛 修复B站获取匿名Cookie逻辑-ExClimbWuzhi 2024-10-24 21:40:32 +08:00
suyiiyii e64fb09145 🐛 修复B站获取匿名Cookie逻辑 2024-10-24 17:43:13 +08:00
suyiiyii d2c33feff8 mock生成匿名Cookie的逻辑 2024-10-23 10:53:11 +08:00
suyiiyii ef52339337 移除用于测试的 token 2024-10-22 21:54:04 +08:00
suyiiyii d614d8bf64 为 bilibili 初步适配Cookie功能 2024-10-22 21:15:37 +08:00
suyiiyii e84894cd9e CookieClientManager中提出_generate_anonymous_cookie方法 2024-10-22 21:13:31 +08:00
suyiiyii ff1c3c3159 WebUI 中,允许查看 Cookie 的 content 2024-10-21 20:58:21 +08:00
suyiiyii 8d32145ea8 ✏️ 改改变量名 2024-10-21 20:43:08 +08:00
suyiiyii f5d30b998c 📝 添加 获取Cookie 的文档 2024-10-21 13:44:46 +08:00
suyiiyii a090ff2127 Merge branch 'MountainDash:main' into cookie 2024-10-21 13:21:44 +08:00
suyiiyii 6474504c30 (admin) 添加验证Cookie有效性 2024-10-21 11:22:54 +08:00
suyiiyii a78bb73281 (admin) 添加验证Cookie有效性接口 2024-10-21 10:04:00 +08:00
suyiiyii c3289671d8 📝 关于 Cookie 的开发指南 2024-10-19 13:25:07 +08:00
suyiiyii 0f4b0aab86 📝 好像还是要加上sass-embedded这个库 2024-10-16 18:15:07 +08:00
suyiiyii 69ef94bcf5 📝 破防了,不整zenuml了 2024-10-16 17:14:59 +08:00
suyiiyii 3c090db0cb 📝 似乎可以了? 2024-10-16 10:41:36 +08:00
suyiiyii 56627753fc 📝 怎么前端编译报错了( 2024-10-16 09:35:59 +08:00
suyiiyii 7359b3ef9d 📝 怎么前端编译报错了( 2024-10-16 09:33:59 +08:00
suyiiyii 7622d3da1e 📝 好像可以用 zenuml 了 ) 2024-10-15 21:43:25 +08:00
suyiiyii 3773c77864 📝 试试zenuml ( 2024-10-15 18:12:53 +08:00
suyiiyii cdc8de9619 📝 试试流程图) 2024-10-14 15:35:29 +08:00
suyiiyii 7aac134d5d 📝 测试mermaid画图 2024-10-14 12:32:59 +08:00
suyiiyii b2b20ab7c5 📝 添加cookie模块使用文档 2024-10-14 01:14:03 +08:00
suyiiyii 2093622672 🐛 改改单测 2024-10-13 21:51:47 +08:00
suyiiyii b6ba904a68 🐛 又忘记改单测了( 2024-10-13 21:30:08 +08:00
suyiiyii f3d8b7d5bc 添加 cookie 时自动使用用户名命名(weibo) 2024-10-13 20:44:37 +08:00
suyiiyii b1b8d37171 (admin) console.log()忘记删了 ( 2024-10-12 13:41:28 +08:00
suyiiyii 271e3e7a72 🗑️ 删除旧的CookieTargetManager 2024-10-12 13:37:17 +08:00
suyiiyii a941d77257 (admin) 支持删除cookieTarget( 2024-10-12 13:35:53 +08:00
suyiiyii 6d8de1b59e (admin) 支持添加cookieTarget 2024-10-12 13:14:04 +08:00
suyiiyii 8174ec895d (admin) 支持查看cookie详情 2024-10-11 13:41:00 +08:00
suyiiyii 10bb6179ae (admin) 支持查看cookie详情 2024-10-11 13:40:31 +08:00
suyiiyii 7030758ac9 (admin) 支持删除cookie 2024-10-11 12:05:28 +08:00
suyiiyii a18b2e4f7b (admin) 支持添加cookie 2024-10-11 11:54:30 +08:00
suyiiyii 3f3cc2d25e 🐛 更改命名siteName以符合小驼峰规范 2024-10-11 11:37:18 +08:00
suyiiyii 5b8d0440ee (admin) 完善 将site选择移动到侧边栏 2024-10-11 11:12:15 +08:00
suyiiyii 24251c2728 (admin) 将site选择移动到侧边栏 2024-10-09 23:23:43 +08:00
suyiiyii 19345cf960 移动validate_cookie到CookieSite中 2024-10-09 23:18:43 +08:00
suyiiyii 1346d07982 修改cookie_site.get_cookie_name为异步 2024-10-09 23:14:17 +08:00
suyiiyii 6c0efdddfc 🔀 merge main 2024-10-08 17:24:34 +08:00
suyiiyii 1d1b9f6574 🐛 config 中添加 clear_db 方法,用于清空数据库内容;添加clear_db fixture,用于在单测前后清空数据库 2024-09-28 16:51:22 +08:00
suyiiyii aa897939d9 为什么 eslint 的warning都不让我过编译 ( 2024-09-27 09:51:19 +08:00
suyiiyii 7d3193d958 为什么前端 pnpm 和 yarn 的行为还不一样( 2024-09-27 01:18:59 +08:00
suyiiyii f31a798326 修修单测 2024-09-27 00:45:45 +08:00
pre-commit-ci[bot] 6b6bf9d8f8 💄 auto fix by pre-commit hooks 2024-09-26 11:41:12 +00:00
suyiiyii 54d37e254d 📝 尝试添加文档 2024-09-26 19:38:43 +08:00
suyiiyii 8fa456bc4e 📝 尝试添加文档 2024-09-26 19:37:06 +08:00
suyiiyii b04cbc2ced 导入导出 cookie 优化代码 2024-09-23 13:49:39 +08:00
suyiiyii 5d160dcadc 导入导出支持 cookie 2024-09-23 11:44:33 +08:00
suyiiyii 8742de6cd1 在 cookie 中添加 cookie_name 字段 2024-09-23 10:29:56 +08:00
suyiiyii 59d42531a3 听劝,修改部分样式 XD 2024-09-22 19:54:17 +08:00
suyiiyii cc31ef88ef 听劝,修改部分样式 XD 2024-09-22 19:49:22 +08:00
suyiiyii 0083f0311a 支持删除 CookieTarget 2024-09-22 17:59:01 +08:00
suyiiyii 6990f04a74 支持删除 CookieTarget 2024-09-22 17:22:14 +08:00
suyiiyii bc44e40f56 支持删除 CookieTarget 2024-09-22 17:12:52 +08:00
suyiiyii bb63529fe8 支持添加 CookieTarget 2024-09-22 17:02:10 +08:00
suyiiyii 75a55c009a 添加 CookieTarget 页面 2024-09-22 14:33:56 +08:00
suyiiyii 4c20e47399 添加 Cookie 增删查 功能 2024-09-22 13:52:51 +08:00
suyiiyii db4b848e3f 添加 Cookie 界面 2024-09-22 13:09:16 +08:00
suyiiyii 54c9020c36 添加cookie页面 2024-09-22 00:28:26 +08:00
suyiiyii 43fb5231b8 🔀 merge 2024-09-21 12:26:36 +08:00
suyiiyii 0aeeb28919 🐛 t 2024-09-21 12:24:45 +08:00
suyiiyii 94daf74359 web api 初步完工 2024-09-20 15:39:22 +08:00
suyiiyii c85e77c801 web api 更新 2024-09-20 00:25:40 +08:00
suyiiyii d890d32bba web api 初稿 2024-09-19 21:16:56 +08:00
suyiiyii 76f271584f web api 初稿 2024-09-19 20:28:16 +08:00
suyiiyii 6cbc6f7d4d 🔀 merge 2024-09-19 10:00:34 +08:00
suyiiyii c784417ecc 初步实现删除cookie的单元测试 2024-09-13 20:01:54 +08:00
suyiiyii dd802a9c17 初步实现添加cookie的单元测试 2024-09-13 19:12:19 +08:00
suyiiyii 2cfd58373f pytest db_config 2024-09-13 14:12:02 +08:00
suyiiyii 4791fb69e0 ♻️ 重构 get_cookie 方法 2024-09-13 11:34:45 +08:00
suyiiyii 4b8d6a9379 🐛 fix 2024-09-13 10:11:54 +08:00
suyiiyii b25fcd9ac2 尝试添加一种可以跳过当前请求的方式 2024-09-13 01:07:34 +08:00
suyiiyii 16331b50d5 根据数据库的修改对应的逻辑,同时移除多余的init_cookie和_check_cookie 2024-09-13 01:00:53 +08:00
suyiiyii af246df222 俺又来改数据库哩 2024-09-13 00:35:14 +08:00
suyiiyii 4f73f8a08c 🐛 弃用_cookie_client_manger_,改用issubclass判断是否为CookieClientManager 2024-09-13 00:26:28 +08:00
suyiiyii 5111baa89c 🐛 应用部分推荐的重命名 2024-09-13 00:11:49 +08:00
suyiiyii f865cef427 🐛 调整日志等级 2024-09-12 23:33:11 +08:00
suyiiyii 318ba8fb3c 🔀 merge 2024-09-09 18:41:01 +08:00
suyiiyii 2c2c9a091c ♻️ del_cookie 2024-09-09 18:36:18 +08:00
suyiiyii 4a5e00c094 :recycles: ddel_cookie_target 2024-09-09 18:32:53 +08:00
suyiiyii 404b1e445c :recycles: add_cookie_target 2024-09-09 18:23:23 +08:00
suyiiyii d43d042618 :recycles: add_cookie 2024-09-09 11:35:39 +08:00
suyiiyii 65a5976897 :recycles: CookieClientManager 2024-09-09 11:06:59 +08:00
suyiiyii f959e3ee08 :recycles: 仿照 platform_manager 添加 site_manager 2024-09-09 11:01:34 +08:00
suyiiyii 4db7e7b911 :recycles: DBConfig中 替换platform_name为site_name 2024-09-08 18:38:38 +08:00
suyiiyii 275bc0cb53 :recycles: 注释掉cookie相关代码,使得bison可以正常运行 2024-09-08 18:21:57 +08:00
suyiiyii ce1f1bbedb 又来改数据库了( 2024-09-08 18:17:06 +08:00
suyiiyii 7c9e191f40 删除cookie 对话 2024-09-08 15:56:44 +08:00
suyiiyii 940301a6fc 取消关联cookie 对话 2024-09-08 15:17:19 +08:00
suyiiyii 61dcf879ce ♻️ 整理代码 2024-09-08 13:03:47 +08:00
suyiiyii a6227828e3 ♻️ 整理代码 2024-09-08 12:59:44 +08:00
suyiiyii bbc5492193 为匿名cookie设置标签 2024-09-08 12:22:06 +08:00
suyiiyii eddd3e42a1 修改_choose_cookie的逻辑以支持no target的Platform 2024-09-06 11:33:39 +08:00
suyiiyii 06079b98f7 关联cookie是不显示匿名cookie 2024-09-06 10:16:24 +08:00
suyiiyii 418a941448 添加不合法cookie的提示 2024-09-06 10:08:08 +08:00
suyiiyii afd1bee762 将get_cookie_friendly_name和valid_cookie移动到ccm内部 2024-09-06 01:08:32 +08:00
suyiiyii b61bde6e3f 关联cookie时,只显示支持的订阅 2024-09-06 00:39:57 +08:00
suyiiyii 6537f01a34 集中判断是否为CookieClientManager 2024-09-06 00:34:52 +08:00
suyiiyii 0ce2893911 匿名cookie和用户cookie一起调度 2024-09-06 00:25:33 +08:00
suyiiyii cf3966e69b 添加cookie只显示支持的Platform 2024-09-06 00:14:35 +08:00
suyiiyii 370fc250f0 数据库Cookie表添加is_universal属性 2024-09-05 19:32:47 +08:00
suyiiyii 3bd0867f0e 数据库Cookie表添加cd属性 2024-09-05 16:07:59 +08:00
suyiiyii 01435eeded 提出assemble_client方法 2024-09-04 01:19:53 +08:00
suyiiyii 498e7d60d4 根据条件选择Cookie 和 状态回写数据库 2024-09-03 13:15:18 +08:00
suyiiyii 055ed6e02a 使用闭包实现client hook 2024-09-03 10:52:20 +08:00
suyiiyii 4ce6b85f79 weibo 带 cookie mvp 2024-09-03 10:00:53 +08:00
suyiiyii 7901b845ea 初步实现携带cookie请求 2024-09-02 23:13:29 +08:00
suyiiyii 1cd778c2e0 ♻️ cookie 组件不再与 user 关联 2024-08-31 23:07:43 +08:00
suyiiyii c828fd94e4 ♻️ cookie 组件不再与 user 关联 2024-08-31 23:04:49 +08:00
suyiiyii ffae6f2ec5 添加cookie的时候显示关联的cookie 2024-08-26 18:09:26 +08:00
suyiiyii 6f20dbf358 支持对话关联cookie到订阅目标 2024-08-26 17:32:36 +08:00
suyiiyii b655eff755 支持对话添加cookie 2024-08-26 10:37:03 +08:00
suyiiyii c264ad374b 🐛 stash 2024-08-22 21:50:25 +08:00
suyiiyii 7913f7485a 添加cookie相关的数据库表 2024-08-22 20:55:39 +08:00
146 changed files with 6356 additions and 4863 deletions
+8 -13
View File
@@ -1,24 +1,19 @@
*.ini
#*.yaml
*.yaml
*.yml
*.md
#*.json
*.json
*.toml
*.xml
tests
node_modules
#admin-frontend
admin-frontend
data*
htmlcov
docker
dist
docs
venv
.venv
/admin-frontend/node_modules
/LICENSE
/.editorconfig
/.gitattributes
/.prettierignore
/.prettierrc
/.devcontainer/
/.github/
.*
!pyproject.toml
!README.md
+3 -14
View File
@@ -6,10 +6,6 @@ inputs:
description: Python version
required: false
default: "3.10"
install-deps:
description: Install dependencies
required: false
default: "false"
runs:
using: "composite"
@@ -18,14 +14,7 @@ runs:
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v4
- name: Setup Poetry
uses: Gr1N/setup-poetry@v9
with:
version: "latest"
enable-cache: true
- name: Install dependencies
if: ${{ inputs.install-deps == 'true' }}
run: uv sync --frozen
shell: bash
poetry-version: "1.7.1"
+26 -16
View File
@@ -11,7 +11,7 @@ on:
- nonebot_bison/**
- tests/**
- pyproject.toml
- uv.lock
- poetry.lock
- docker.env.prod
- .github/**
pull_request:
@@ -21,7 +21,7 @@ on:
- nonebot_bison/**
- tests/**
- pyproject.toml
- uv.lock
- poetry.lock
- docker.env.prod
- .github/**
types:
@@ -72,16 +72,15 @@ jobs:
uses: ./.github/actions/setup-python
with:
python-version: ${{ matrix.python-version }}
install-deps: "true"
- name: Install playwright
run: uv run playwright install
- name: Install prerequisites
run: poetry install
- name: Run Pytest
run: uv run pytest --cov-report xml --cov=./nonebot_bison -k 'not compare and not render' -n auto
run: poetry run pytest --cov-report xml --cov=./nonebot_bison -k 'not compare and not render' -n auto
- name: Upload coverage report
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: smoke-test
@@ -107,16 +106,15 @@ jobs:
uses: ./.github/actions/setup-python
with:
python-version: ${{ matrix.python-version }}
install-deps: "true"
- name: Install playwright
run: uv run playwright install
- name: Install prerequisites
run: poetry install
- name: Run Pytest
run: uv run pytest --cov-report xml --cov=./nonebot_bison -k 'not compare' -n auto
run: poetry run pytest --cov-report xml --cov=./nonebot_bison -k 'not compare' -n auto
- name: Upload coverage report
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: all-test
@@ -129,6 +127,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Download frontend files
uses: actions/download-artifact@v4
with:
name: frontend
path: ./nonebot_bison/admin_page/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -140,7 +144,7 @@ jobs:
if: github.event_name == 'pull_request'
with:
context: .
file: ./docker/Dockerfile
file: ./docker/Dockerfile_with_frontend
push: false
load: true
tags: felinae98/nonebot-bison:dummy
@@ -170,7 +174,7 @@ jobs:
if: github.event_name != 'pull_request'
with:
context: .
file: ./docker/Dockerfile
file: ./docker/Dockerfile_with_frontend
push: true
tags: felinae98/nonebot-bison:${{ env.GIT_BRANCH_NAME }}
cache-from: type=gha
@@ -184,6 +188,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Download frontend files
uses: actions/download-artifact@v4
with:
name: frontend
path: ./nonebot_bison/admin_page/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -205,8 +215,8 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile_without_browser
file: ./docker/Dockerfile_with_frontend_sentry
push: ${{ github.event_name != 'pull_request' }}
tags: felinae98/nonebot-bison:${{ env.GIT_BRANCH_NAME }}-nobrowser
tags: felinae98/nonebot-bison:${{ env.GIT_BRANCH_NAME }}-sentry
cache-from: type=gha
cache-to: type=gha,mode=max
+33 -3
View File
@@ -9,12 +9,35 @@ on:
type: string
jobs:
build-frontend:
name: Build Frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Frontend
uses: ./.github/actions/build-frontend
- name: Upload dist
uses: actions/upload-artifact@v4
with:
name: frontend
path: ./admin-frontend/build/
docker-main:
name: Docker main
runs-on: ubuntu-latest
needs: [build-frontend]
steps:
- uses: actions/checkout@v4
- name: Download frontend files
uses: actions/download-artifact@v4
with:
name: frontend
path: ./src/plugins/nonebot_bison/admin_page/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -31,7 +54,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
file: ./docker/Dockerfile_with_frontend
push: true
tags: felinae98/nonebot-bison:${{ inputs.dockerTag }}
cache-from: type=gha
@@ -40,9 +63,16 @@ jobs:
docker-main-sentry:
name: Docker main sentry
runs-on: ubuntu-latest
needs: [build-frontend]
steps:
- uses: actions/checkout@v4
- name: Download frontend files
uses: actions/download-artifact@v4
with:
name: frontend
path: ./src/plugins/nonebot_bison/admin_page/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -59,7 +89,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile_without_browser
tags: felinae98/nonebot-bison:${{ inputs.dockerTag }}-nobrowser
file: ./docker/Dockerfile_with_frontend_sentry
tags: felinae98/nonebot-bison:${{ inputs.dockerTag }}-sentry
cache-from: type=gha
cache-to: type=gha,mode=max
+4 -7
View File
@@ -11,7 +11,7 @@ on:
- nonebot_bison/**
- tests/**
- pyproject.toml
- uv.lock
- poetry.lock
- docker.env.prod
- .github/**
pull_request:
@@ -21,7 +21,7 @@ on:
- nonebot_bison/**
- tests/**
- pyproject.toml
- uv.lock
- poetry.lock
- docker.env.prod
- .github/**
types:
@@ -55,10 +55,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install prerequisites
run: uv add pydantic==1.10 && uv sync --frozen
- name: Install playwright
run: uv run playwright install
run: poetry add pydantic@^1.10 && poetry install
- name: Run Pytest
run: uv run pytest -k 'not compare and not render' -n auto
run: poetry run pytest -k 'not compare and not render' -n auto
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
- name: Setup Python environment
uses: ./.github/actions/setup-python
- run: echo "TAG_NAME=v$(uvx --from=toml-cli toml get --toml-path=pyproject.toml project.version)" >> $GITHUB_ENV
- run: echo "TAG_NAME=v$(poetry version -s)" >> $GITHUB_ENV
- name: Archive Changelog
uses: docker://ghcr.io/nonebot/auto-changelog:master
@@ -30,6 +30,6 @@ jobs:
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git add .
git commit -m ":bookmark: Release ${{ env.TAG_NAME }}"
git commit -m ":bookmark: Release $(poetry version -s)"
git tag ${{ env.TAG_NAME }}
git push && git push --tags
+12 -5
View File
@@ -54,17 +54,24 @@ jobs:
- name: Publish PyPI and Github
run: |
uv publish --build -u ${{ secrets.PYPI_USERNAME }} -p ${{ secrets.PYPI_PASSWORD }} || echo "Already pushed to pypi"
poetry publish --build -u ${{ secrets.PYPI_USERNAME }} -p ${{ secrets.PYPI_PASSWORD }} || echo "Already pushed to pypi"
gh release upload --clobber ${{ env.TAG_NAME }} dist/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-docker:
runs-on: ubuntu-latest
needs: build-frontend
steps:
- uses: actions/checkout@v4
- name: Download frontend files
uses: actions/download-artifact@v4
with:
name: frontend
path: ./nonebot_bison/admin_page/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -85,7 +92,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
file: ./docker/Dockerfile_with_frontend
push: true
tags: |
felinae98/nonebot-bison:latest
@@ -97,10 +104,10 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile_without_browser
file: ./docker/Dockerfile_with_frontend_sentry
push: true
tags: |
felinae98/nonebot-bison:${{ env.TAG_NAME }}-nobrowser
felinae98/nonebot-bison:nobrowser
felinae98/nonebot-bison:${{ env.TAG_NAME }}-sentry
felinae98/nonebot-bison:sentry
cache-from: type=gha
cache-to: type=gha,mode=max
+1 -6
View File
@@ -19,9 +19,4 @@ jobs:
- uses: actions/checkout@v4
- name: Run Ruff Lint
uses: astral-sh/ruff-action@v2
with:
src: >-
nonebot_bison/
extra_plugins/
tests/
uses: chartboost/ruff-action@v1
+17 -7
View File
@@ -7,13 +7,23 @@ ci:
autoupdate_commit_msg: ":arrow_up: auto update by pre-commit hooks"
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.2
rev: v0.6.3
hooks:
- id: ruff
args: [--fix]
stages: [pre-commit]
- id: ruff-format
stages: [pre-commit]
args: [--fix, --exit-non-zero-on-fix]
stages: [commit]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
stages: [commit]
- repo: https://github.com/psf/black
rev: 24.8.0
hooks:
- id: black
stages: [commit]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
@@ -21,10 +31,10 @@ repos:
- id: prettier
types_or: [javascript, jsx, ts, tsx, markdown, yaml, json]
exclude: "admin-frontend/"
stages: [pre-commit]
stages: [commit]
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.16.0
rev: v9.9.1
hooks:
- id: eslint
additional_dependencies:
-13
View File
@@ -1,18 +1,5 @@
# Change Log
## 最近更新
### 新功能
- :sparkles: B站获取OPUS格式动态 [@AzideCupric](https://github.com/AzideCupric) ([#651](https://github.com/MountainDash/nonebot-bison/pull/651))
- :sparkles: 添加 Cookie 组件 [@suyiiyii](https://github.com/suyiiyii) ([#633](https://github.com/MountainDash/nonebot-bison/pull/633))
### Bug 修复
- :bug: 修复 cookie 模块 type hint [@suyiiyii](https://github.com/suyiiyii) ([#658](https://github.com/MountainDash/nonebot-bison/pull/658))
- :bug: B站转发动态补充 DeletedItem 类型解析 [@AzideCupric](https://github.com/AzideCupric) ([#659](https://github.com/MountainDash/nonebot-bison/pull/659))
- :bug: 小刻食堂cdn使用https [@phidiaLam](https://github.com/phidiaLam) ([#650](https://github.com/MountainDash/nonebot-bison/pull/650))
## v0.9.5
### 新功能
+3
View File
@@ -17,6 +17,9 @@ _✨ 通用订阅推送插件 ✨_
<img src="https://img.shields.io/pypi/v/nonebot-bison?logo=python&logoColor=edb641" alt="pypi">
</a>
<img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=edb641" alt="python">
<a href="https://github.com/psf/black">
<img src="https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=edb641" alt="black">
</a>
<a href="https://github.com/astral-sh/ruff">
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="ruff">
</a>
+2 -2
View File
@@ -14,7 +14,7 @@
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.13",
"@types/node": "^22.9.0",
"@types/node": "^20.16.5",
"@types/react": "^18.3.7",
"@types/react-dom": "^18.3.0",
"react": "^18.3.1",
@@ -25,7 +25,7 @@
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"typescript": "^5.6.2",
"web-vitals": "^4.2.4"
"web-vitals": "^3.5.2"
},
"scripts": {
"start": "react-scripts start",
+69 -70
View File
@@ -36,8 +36,8 @@ importers:
specifier: ^29.5.13
version: 29.5.13
'@types/node':
specifier: ^22.9.0
version: 22.9.0
specifier: ^20.16.5
version: 20.16.5
'@types/react':
specifier: ^18.3.7
version: 18.3.7
@@ -58,7 +58,7 @@ importers:
version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-scripts:
specifier: 5.0.1
version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@types/babel__core@7.1.20)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.6.2)
version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@types/babel__core@7.1.20)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.6.2)
redux:
specifier: ^5.0.1
version: 5.0.1
@@ -69,8 +69,8 @@ importers:
specifier: ^5.6.2
version: 5.6.2
web-vitals:
specifier: ^4.2.4
version: 4.2.4
specifier: ^3.5.2
version: 3.5.2
devDependencies:
'@testing-library/jest-dom':
specifier: ^6.5.0
@@ -86,10 +86,10 @@ importers:
version: 8.57.1
eslint-config-airbnb:
specifier: ^19.0.4
version: 19.0.4(eslint-plugin-import@2.30.0)(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.36.1(eslint@8.57.1))(eslint@8.57.1)
version: 19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.36.1(eslint@8.57.1))(eslint@8.57.1)
eslint-config-airbnb-typescript:
specifier: ^18.0.0
version: 18.0.0(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1)
version: 18.0.0(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1)
eslint-import-resolver-typescript:
specifier: ^3.6.3
version: 3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1)
@@ -1362,8 +1362,8 @@ packages:
'@types/mime@3.0.1':
resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==}
'@types/node@22.9.0':
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
'@types/node@20.16.5':
resolution: {integrity: sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==}
'@types/parse-json@4.0.0':
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
@@ -2827,7 +2827,6 @@ packages:
eslint@8.57.1:
resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
hasBin: true
espree@9.6.1:
@@ -3209,8 +3208,8 @@ packages:
resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}
engines: {node: '>= 6'}
http-proxy-middleware@2.0.7:
resolution: {integrity: sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==}
http-proxy-middleware@2.0.6:
resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/express': ^4.17.13
@@ -5668,8 +5667,8 @@ packages:
wbuf@1.7.3:
resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==}
web-vitals@4.2.4:
resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
web-vitals@3.5.2:
resolution: {integrity: sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==}
webidl-conversions@4.0.2:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
@@ -6980,7 +6979,7 @@ snapshots:
'@jest/console@27.5.1':
dependencies:
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
jest-message-util: 27.5.1
jest-util: 27.5.1
@@ -6989,7 +6988,7 @@ snapshots:
'@jest/console@28.1.3':
dependencies:
'@jest/types': 28.1.3
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
jest-message-util: 28.1.3
jest-util: 28.1.3
@@ -7002,7 +7001,7 @@ snapshots:
'@jest/test-result': 27.5.1
'@jest/transform': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.8.1
@@ -7036,7 +7035,7 @@ snapshots:
dependencies:
'@jest/fake-timers': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
jest-mock: 27.5.1
'@jest/expect-utils@29.7.0':
@@ -7047,7 +7046,7 @@ snapshots:
dependencies:
'@jest/types': 27.5.1
'@sinonjs/fake-timers': 8.1.0
'@types/node': 22.9.0
'@types/node': 20.16.5
jest-message-util: 27.5.1
jest-mock: 27.5.1
jest-util: 27.5.1
@@ -7065,7 +7064,7 @@ snapshots:
'@jest/test-result': 27.5.1
'@jest/transform': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
collect-v8-coverage: 1.0.1
exit: 0.1.2
@@ -7149,7 +7148,7 @@ snapshots:
dependencies:
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/yargs': 16.0.9
chalk: 4.1.2
@@ -7158,7 +7157,7 @@ snapshots:
'@jest/schemas': 28.1.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/yargs': 17.0.32
chalk: 4.1.2
@@ -7167,7 +7166,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/yargs': 17.0.32
chalk: 4.1.2
@@ -7436,20 +7435,20 @@ snapshots:
'@types/body-parser@1.19.2':
dependencies:
'@types/connect': 3.4.35
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/bonjour@3.5.10':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/connect-history-api-fallback@1.3.5':
dependencies:
'@types/express-serve-static-core': 4.17.31
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/connect@3.4.35':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/eslint@8.4.10':
dependencies:
@@ -7464,7 +7463,7 @@ snapshots:
'@types/express-serve-static-core@4.17.31':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
@@ -7477,13 +7476,13 @@ snapshots:
'@types/graceful-fs@4.1.5':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/html-minifier-terser@6.1.0': {}
'@types/http-proxy@1.17.9':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/istanbul-lib-coverage@2.0.6': {}
@@ -7506,7 +7505,7 @@ snapshots:
'@types/mime@3.0.1': {}
'@types/node@22.9.0':
'@types/node@20.16.5':
dependencies:
undici-types: 6.19.8
@@ -7533,7 +7532,7 @@ snapshots:
'@types/resolve@1.17.1':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/retry@0.12.0': {}
@@ -7546,11 +7545,11 @@ snapshots:
'@types/serve-static@1.15.0':
dependencies:
'@types/mime': 3.0.1
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/sockjs@0.3.33':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/stack-utils@2.0.3': {}
@@ -7560,7 +7559,7 @@ snapshots:
'@types/ws@8.5.3':
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
'@types/yargs-parser@21.0.3': {}
@@ -9098,7 +9097,7 @@ snapshots:
optionalDependencies:
source-map: 0.6.1
eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0)(eslint@8.57.1):
eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
confusing-browser-globals: 1.0.11
eslint: 8.57.1
@@ -9107,19 +9106,19 @@ snapshots:
object.entries: 1.1.7
semver: 6.3.1
eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1):
eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 8.6.0(eslint@8.57.1)(typescript@5.6.2)
eslint: 8.57.1
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0)(eslint@8.57.1)
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1)
transitivePeerDependencies:
- eslint-plugin-import
eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0)(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.36.1(eslint@8.57.1))(eslint@8.57.1):
eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.36.1(eslint@8.57.1))(eslint@8.57.1):
dependencies:
eslint: 8.57.1
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0)(eslint@8.57.1)
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
eslint-plugin-react: 7.36.1(eslint@8.57.1)
@@ -9127,7 +9126,7 @@ snapshots:
object.assign: 4.1.4
object.entries: 1.1.6
eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(jest@27.5.1)(typescript@5.6.2):
eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)(jest@27.5.1)(typescript@5.6.2):
dependencies:
'@babel/core': 7.25.2
'@babel/eslint-parser': 7.19.1(@babel/core@7.25.2)(eslint@8.57.1)
@@ -9138,7 +9137,7 @@ snapshots:
confusing-browser-globals: 1.0.11
eslint: 8.57.1
eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint@8.57.1)
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(jest@27.5.1)(typescript@5.6.2)
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
eslint-plugin-react: 7.36.1(eslint@8.57.1)
@@ -9168,7 +9167,7 @@ snapshots:
debug: 4.3.5
enhanced-resolve: 5.17.1
eslint: 8.57.1
eslint-module-utils: 2.8.1(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-module-utils: 2.8.1(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
fast-glob: 3.3.2
get-tsconfig: 4.8.0
is-bun-module: 1.1.0
@@ -9181,7 +9180,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
eslint-module-utils@2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
eslint-module-utils@2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -9192,7 +9191,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.11.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
eslint-module-utils@2.11.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -9203,7 +9202,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.8.1(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
eslint-module-utils@2.8.1(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -9221,7 +9220,7 @@ snapshots:
lodash: 4.17.21
string-natural-compare: 3.0.1
eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -9232,7 +9231,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -9260,7 +9259,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -9862,7 +9861,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
http-proxy-middleware@2.0.7(@types/express@4.17.14):
http-proxy-middleware@2.0.6(@types/express@4.17.14):
dependencies:
'@types/http-proxy': 1.17.9
http-proxy: 1.18.1
@@ -10146,7 +10145,7 @@ snapshots:
'@jest/environment': 27.5.1
'@jest/test-result': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
co: 4.6.0
dedent: 0.7.0
@@ -10249,7 +10248,7 @@ snapshots:
'@jest/environment': 27.5.1
'@jest/fake-timers': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
jest-mock: 27.5.1
jest-util: 27.5.1
jsdom: 16.7.0
@@ -10264,7 +10263,7 @@ snapshots:
'@jest/environment': 27.5.1
'@jest/fake-timers': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
jest-mock: 27.5.1
jest-util: 27.5.1
@@ -10276,7 +10275,7 @@ snapshots:
dependencies:
'@jest/types': 27.5.1
'@types/graceful-fs': 4.1.5
'@types/node': 22.9.0
'@types/node': 20.16.5
anymatch: 3.1.2
fb-watchman: 2.0.2
graceful-fs: 4.2.11
@@ -10295,7 +10294,7 @@ snapshots:
'@jest/source-map': 27.5.1
'@jest/test-result': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
co: 4.6.0
expect: 27.5.1
@@ -10369,7 +10368,7 @@ snapshots:
jest-mock@27.5.1:
dependencies:
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
jest-pnp-resolver@1.2.2(jest-resolve@27.5.1):
optionalDependencies:
@@ -10407,7 +10406,7 @@ snapshots:
'@jest/test-result': 27.5.1
'@jest/transform': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
emittery: 0.8.1
graceful-fs: 4.2.11
@@ -10458,7 +10457,7 @@ snapshots:
jest-serializer@27.5.1:
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
graceful-fs: 4.2.11
jest-snapshot@27.5.1:
@@ -10491,7 +10490,7 @@ snapshots:
jest-util@27.5.1:
dependencies:
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -10500,7 +10499,7 @@ snapshots:
jest-util@28.1.3:
dependencies:
'@jest/types': 28.1.3
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -10509,7 +10508,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.9.0
'@types/node': 20.16.5
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -10539,7 +10538,7 @@ snapshots:
dependencies:
'@jest/test-result': 27.5.1
'@jest/types': 27.5.1
'@types/node': 22.9.0
'@types/node': 20.16.5
ansi-escapes: 4.3.2
chalk: 4.1.2
jest-util: 27.5.1
@@ -10549,7 +10548,7 @@ snapshots:
dependencies:
'@jest/test-result': 28.1.3
'@jest/types': 28.1.3
'@types/node': 22.9.0
'@types/node': 20.16.5
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.10.2
@@ -10558,19 +10557,19 @@ snapshots:
jest-worker@26.6.2:
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
merge-stream: 2.0.0
supports-color: 7.2.0
jest-worker@27.5.1:
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
merge-stream: 2.0.0
supports-color: 8.1.1
jest-worker@28.1.3:
dependencies:
'@types/node': 22.9.0
'@types/node': 20.16.5
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -11682,7 +11681,7 @@ snapshots:
'@remix-run/router': 1.19.2
react: 18.3.1
react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@types/babel__core@7.1.20)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.6.2):
react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@types/babel__core@7.1.20)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.6.2):
dependencies:
'@babel/core': 7.25.2
'@pmmmwh/react-refresh-webpack-plugin': 0.5.9(react-refresh@0.11.0)(type-fest@0.21.3)(webpack-dev-server@4.11.1(webpack@5.94.0))(webpack@5.94.0)
@@ -11700,7 +11699,7 @@ snapshots:
dotenv: 10.0.0
dotenv-expand: 5.1.0
eslint: 8.57.1
eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(jest@27.5.1)(typescript@5.6.2)
eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)(jest@27.5.1)(typescript@5.6.2)
eslint-webpack-plugin: 3.2.0(eslint@8.57.1)(webpack@5.94.0)
file-loader: 6.2.0(webpack@5.94.0)
fs-extra: 10.1.0
@@ -12704,7 +12703,7 @@ snapshots:
dependencies:
minimalistic-assert: 1.0.1
web-vitals@4.2.4: {}
web-vitals@3.5.2: {}
webidl-conversions@4.0.2: {}
@@ -12740,7 +12739,7 @@ snapshots:
express: 4.19.2
graceful-fs: 4.2.11
html-entities: 2.3.3
http-proxy-middleware: 2.0.7(@types/express@4.17.14)
http-proxy-middleware: 2.0.6(@types/express@4.17.14)
ipaddr.js: 2.0.1
open: 8.4.0
p-retry: 4.6.2
+14 -190
View File
@@ -1,192 +1,16 @@
# syntax=docker/dockerfile:1.10
FROM python:3.12-slim AS metadata-stage
WORKDIR /tmp
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
TZ=Asia/Shanghai
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
python3-pip \
git \
&& pip install toml \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY ./pyproject.toml ./
RUN echo "📋 Collecting metadata..." && \
export CREATED_DATE="$(date -u '+%Y-%m-%d %H:%M:%S UTC')" && \
export PYPROJECT_NAME=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["name"])') && \
export DESCRIPTION=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["description"])') && \
export AUTHOR=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["authors"][0]["name"])') && \
echo "⏰ Created Date: $CREATED_DATE" && \
echo "📝 Project Name: $PYPROJECT_NAME" && \
echo "📄 Description: $DESCRIPTION" && \
echo "👤 Author: $AUTHOR" && \
echo "$CREATED_DATE" > /tmp/CREATED_DATE && \
echo "$PYPROJECT_NAME" > /tmp/PYPROJECT_NAME && \
echo "$DESCRIPTION" > /tmp/DESCRIPTION && \
echo "$AUTHOR" > /tmp/AUTHOR
RUN --mount=type=bind,source=./.git/,target=/tmp/.git/ \
echo "🏷️ Checking version information..." && \
VERSION=$(git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD || echo "unknown") && \
echo "📌 Version: $VERSION" && \
echo "$VERSION" > /tmp/VERSION
LABEL org.opencontainers.image.created="$(cat /tmp/CREATED_DATE)" \
org.opencontainers.image.authors="$(cat /tmp/AUTHOR)" \
org.opencontainers.image.description="$(cat /tmp/DESCRIPTION)" \
org.opencontainers.image.name="$(cat /tmp/PYPROJECT_NAME)" \
org.opencontainers.image.version="$(cat /tmp/VERSION)"
FROM node:20-slim AS frontend-stage
WORKDIR /tmp/admin-frontend
ENV TZ=Asia/Shanghai \
PNPM_HOME="/pnpm" \
PATH="$PNPM_HOME:$PATH"
COPY ./admin-frontend/package.json ./admin-frontend/pnpm-lock.yaml ./
RUN corepack enable && \
corepack prepare pnpm@9.15.1 --activate && \
echo "🔔 Verifying Node.js installation..." && \
if NODE_VERSION=$(node --version 2>&1); then \
echo "✅ Node.js version ${NODE_VERSION} installed successfully"; \
else \
echo "❌ Node.js installation failed" && exit 1; \
fi && \
echo "🔔 Verifying pnpm installation..." && \
if PNPM_VERSION=$(pnpm --version 2>&1); then \
echo "✅ pnpm version ${PNPM_VERSION} installed successfully"; \
else \
echo "❌ pnpm installation failed" && exit 1; \
fi
RUN pnpm install --frozen-lockfile
COPY ./admin-frontend .
RUN mkdir -p ../nonebot_bison/admin_page/dist
RUN echo "🏗️ Starting frontend build..." && \
pnpm run build && \
echo "✅ Frontend build completed"
FROM python:3.12-slim AS playwright-stage
WORKDIR /tmp
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
TZ=Asia/Shanghai
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN echo "📦 Installing playwright..." && \
uvx playwright install --with-deps chromium && \
echo "✅ Playwright installed successfully"
FROM python:3.12-slim AS production
FROM node:20.17.0 as frontend
ADD . /app
WORKDIR /app/admin-frontend
RUN npm install -g pnpm
RUN pnpm install && pnpm build
FROM python:3.11
RUN python3 -m pip install poetry && poetry config virtualenvs.create false
WORKDIR /app
#ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
ENV DEBIAN_FRONTEND=noninteractive \
UV_COMPILE_BYTECODE=1 \
UV_SYSTEM_PYTHON=true \
PYTHONUNBUFFERED=1 \
UV_LINK_MODE=copy \
TZ=Asia/Shanghai \
SHELL="/bin/bash"
RUN echo "📦 Installing system dependencies..." && \
apt-get update && \
apt-get install -y --no-install-recommends \
curl \
xvfb \
fonts-noto-color-emoji \
fonts-unifont \
libfontconfig1 \
libfreetype6 \
xfonts-scalable \
fonts-liberation \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-tlwg-loma-otf \
at-spi2-common \
fonts-freefont-ttf \
libasound2 \
libasound2-data \
libatk-bridge2.0-0 \
libatk1.0-0 \
libatspi2.0-0 \
libavahi-client3 \
libavahi-common-data \
libavahi-common3 \
libcairo2 \
libcups2 \
libdatrie1 \
libdbus-1-3 \
libfribidi0 \
libgbm1 \
libglib2.0-0 \
libgraphite2-3 \
libharfbuzz0b \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libthai-data \
libthai0 \
libwayland-server0 \
libxcb-render0 \
libxcomposite1 \
libxdamage1 \
libxi6 \
libxkbcommon0 && \
fc-cache -fv && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
echo "✅ System dependencies installed successfully"
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN echo "🔔 Verifying uv installation..." && \
if UV_VERSION=$(uv --version 2>&1); then \
echo "✅ uv version ${UV_VERSION} installed successfully"; \
else \
echo "❌ uv installation failed" && exit 1; \
fi
COPY ./pyproject.toml ./uv.lock ./
RUN --mount=type=cache,target=/root/.cache/ \
--mount=type=cache,target=/root/.uv \
echo "📦 Installing bison dependencies..." && \
uv pip install --extra=docker --requirement pyproject.toml --no-cache && \
echo "✅ Dependencies installed successfully" && \
echo "🔔 Cleaning up uv..." && \
rm -rf /bin/uv /bin/uvx && \
echo "✅ UV cleanup completed"
COPY --from=metadata-stage /tmp/VERSION /app/VERSION
COPY nonebot_bison/ /app/nonebot_bison/
COPY --from=frontend-stage /tmp/nonebot_bison/admin_page/dist ./nonebot_bison/admin_page/dist
COPY --from=playwright-stage /root/.cache/ms-playwright /root/.cache/ms-playwright
EXPOSE 8080
RUN echo '#!/bin/bash' > /app/start.sh && \
echo 'echo "📌 Current bison Version: $(cat /app/VERSION)"' >> /app/start.sh && \
echo 'echo "🚀 Starting service..."' >> /app/start.sh && \
echo 'nb run' >> /app/start.sh && \
chmod +x /app/start.sh
CMD ["/app/start.sh"]
COPY ./README.md ./pyproject.toml ./poetry.lock* /app/
RUN poetry install --only=main,docker
ADD src /app/src
ADD bot.py /app/
COPY --from=frontend /app/nonebot_bison/admin_page/dist /app/nonebot_bison/admin_page/dist
ENV HOST=0.0.0.0
CMD ["nb", "run"]
+10
View File
@@ -0,0 +1,10 @@
FROM python:3.11
RUN apt-get update && apt-get install -y fonts-wqy-microhei chromium nano
RUN python3 -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
RUN python3 -m pip install poetry && poetry config virtualenvs.create false
WORKDIR /app
COPY ./README.md ./pyproject.toml ./poetry.lock* /app/
RUN poetry install --only=main,docker
ENV BISON_BROWSER=local:/usr/bin/chromium
ADD src /app/src
ENV HOST=0.0.0.0
+9
View File
@@ -0,0 +1,9 @@
FROM python:3.11
RUN python3 -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
RUN python3 -m pip install poetry && poetry config virtualenvs.create false
WORKDIR /app
COPY ./README.md ./pyproject.toml ./poetry.lock* /app/
RUN poetry install --only=main,docker
ADD src /app/src
ENV HOST=0.0.0.0
CMD ["nb", "run"]
+50
View File
@@ -0,0 +1,50 @@
# syntax=docker/dockerfile:1.10
FROM python:3.11-slim-bullseye as base
FROM base as builder
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=false \
PATH="$PATH:/runtime/bin" \
PYTHONPATH="$PYTHONPATH:/runtime/lib/python3.10/site-packages" \
# Versions:
POETRY_VERSION=1.7.1
RUN apt-get update && apt-get install -y build-essential unzip wget python-dev git
RUN pip install "poetry==$POETRY_VERSION"
WORKDIR /src
COPY README.md pyproject.toml poetry.lock /src/
RUN poetry export --only=main,docker --without-hashes --no-interaction --no-ansi -f requirements.txt -o requirements.txt
RUN pip install --prefix=/runtime --force-reinstall -r requirements.txt
FROM base as runtime
WORKDIR /app
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont \
libfontconfig1 libfreetype6 xfonts-cyrillic xfonts-scalable fonts-liberation \
fonts-ipafont-gothic fonts-wqy-zenhei fonts-tlwg-loma-otf \
fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 \
libcairo2 libcups2 libdbus-1-3 libdrm2 libegl1 libgbm1 libglib2.0-0 libgtk-3-0 \
libnspr4 libnss3 libpango-1.0-0 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxdamage1 libxext6 libxfixes3 libxrandr2 libxshmfence1 nano
COPY --from=builder /runtime /usr/local
ADD . /app/
RUN pip install -e . && playwright install chromium
RUN mv docker.env.prod .env.prod && \
nb adapter install nonebot-adapter-red && \
nb adapter install nonebot-adapter-qq
ENV HOST=0.0.0.0
CMD ["nb", "run"]
# vim: ft=dockerfile
+51
View File
@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:1.10
FROM python:3.11-slim-bullseye as base
FROM base as builder
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=false \
PATH="$PATH:/runtime/bin" \
PYTHONPATH="$PYTHONPATH:/runtime/lib/python3.10/site-packages" \
# Versions:
POETRY_VERSION=1.7.1
RUN apt-get update && apt-get install -y build-essential unzip wget python3-dev git
RUN pip install "poetry==$POETRY_VERSION"
WORKDIR /src
COPY pyproject.toml poetry.lock /src/
RUN poetry export --only=main,docker --without-hashes --no-interaction --no-ansi -f requirements.txt -o requirements.txt
RUN pip install --prefix=/runtime --force-reinstall -r requirements.txt
FROM base as runtime
WORKDIR /app
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont \
libfontconfig1 libfreetype6 xfonts-cyrillic xfonts-scalable fonts-liberation \
fonts-ipafont-gothic fonts-wqy-zenhei fonts-tlwg-loma-otf \
fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 \
libcairo2 libcups2 libdbus-1-3 libdrm2 libegl1 libgbm1 libglib2.0-0 libgtk-3-0 \
libnspr4 libnss3 libpango-1.0-0 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxdamage1 libxext6 libxfixes3 libxrandr2 libxshmfence1 nano
COPY --from=builder /runtime /usr/local
ADD . /app/
RUN pip install -e . && playwright install chromium
RUN mv docker.env.prod .env.prod && \
nb adapter install nonebot-adapter-red && \
nb adapter install nonebot-adapter-qq && \
nb plugin install nonebot-plugin-sentry
ENV HOST=0.0.0.0
CMD ["nb", "run"]
# vim: ft=dockerfile
-145
View File
@@ -1,145 +0,0 @@
# syntax=docker/dockerfile:1.10
FROM python:3.12-slim AS metadata-stage
WORKDIR /tmp
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
TZ=Asia/Shanghai
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
python3-pip \
git \
&& pip install toml \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY ./pyproject.toml ./
RUN echo "📋 Collecting metadata..." && \
export CREATED_DATE="$(date -u '+%Y-%m-%d %H:%M:%S UTC')" && \
export PYPROJECT_NAME=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["name"])') && \
export DESCRIPTION=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["description"])') && \
export AUTHOR=$(python3 -c 'import toml; print(toml.load("pyproject.toml")["project"]["authors"][0]["name"])') && \
echo "⏰ Created Date: $CREATED_DATE" && \
echo "📝 Project Name: $PYPROJECT_NAME" && \
echo "📄 Description: $DESCRIPTION" && \
echo "👤 Author: $AUTHOR" && \
echo "$CREATED_DATE" > /tmp/CREATED_DATE && \
echo "$PYPROJECT_NAME" > /tmp/PYPROJECT_NAME && \
echo "$DESCRIPTION" > /tmp/DESCRIPTION && \
echo "$AUTHOR" > /tmp/AUTHOR
RUN --mount=type=bind,source=./.git/,target=/tmp/.git/ \
echo "🏷️ Checking version information..." && \
VERSION=$(git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD || echo "unknown") && \
echo "📌 Version: $VERSION" && \
echo "$VERSION" > /tmp/VERSION
LABEL org.opencontainers.image.created="$(cat /tmp/CREATED_DATE)" \
org.opencontainers.image.authors="$(cat /tmp/AUTHOR)" \
org.opencontainers.image.description="$(cat /tmp/DESCRIPTION)" \
org.opencontainers.image.name="$(cat /tmp/PYPROJECT_NAME)" \
org.opencontainers.image.version="$(cat /tmp/VERSION)"
FROM node:20-slim AS frontend-stage
WORKDIR /tmp/admin-frontend
ENV TZ=Asia/Shanghai \
PNPM_HOME="/pnpm" \
PATH="$PNPM_HOME:$PATH"
COPY ./admin-frontend/package.json ./admin-frontend/pnpm-lock.yaml ./
RUN corepack enable && \
corepack prepare pnpm@9.15.1 --activate && \
echo "🔔 Verifying Node.js installation..." && \
if NODE_VERSION=$(node --version 2>&1); then \
echo "✅ Node.js version ${NODE_VERSION} installed successfully"; \
else \
echo "❌ Node.js installation failed" && exit 1; \
fi && \
echo "🔔 Verifying pnpm installation..." && \
if PNPM_VERSION=$(pnpm --version 2>&1); then \
echo "✅ pnpm version ${PNPM_VERSION} installed successfully"; \
else \
echo "❌ pnpm installation failed" && exit 1; \
fi
RUN pnpm install --frozen-lockfile
COPY ./admin-frontend .
RUN mkdir -p ../nonebot_bison/admin_page/dist
RUN echo "🏗️ Starting frontend build..." && \
pnpm run build && \
echo "✅ Frontend build completed"
FROM python:3.12-slim AS playwright-stage
WORKDIR /tmp
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
TZ=Asia/Shanghai
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN echo "📦 Installing playwright..." && \
uvx playwright install --with-deps chromium && \
echo "✅ Playwright installed successfully"
FROM python:3.12-slim AS production
WORKDIR /app
ENV DEBIAN_FRONTEND=noninteractive \
UV_COMPILE_BYTECODE=1 \
UV_SYSTEM_PYTHON=true \
PYTHONUNBUFFERED=1 \
UV_LINK_MODE=copy \
TZ=Asia/Shanghai \
SHELL="/bin/bash"
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN echo "🔔 Verifying uv installation..." && \
if UV_VERSION=$(uv --version 2>&1); then \
echo "✅ uv version ${UV_VERSION} installed successfully"; \
else \
echo "❌ uv installation failed" && exit 1; \
fi
COPY ./pyproject.toml ./uv.lock ./
COPY ./docker.env.prod ./.env
RUN --mount=type=cache,target=/root/.cache/ \
--mount=type=cache,target=/root/.uv \
echo "📦 Installing bison dependencies..." && \
uv pip install --extra=docker --requirement pyproject.toml --no-cache && \
echo "✅ Dependencies installed successfully" && \
echo "🔔 Cleaning up uv..." && \
rm -rf /bin/uv /bin/uvx && \
echo "✅ UV cleanup completed"
COPY --from=metadata-stage /tmp/VERSION /app/VERSION
COPY nonebot_bison/ /app/nonebot_bison/
COPY --from=frontend-stage /tmp/nonebot_bison/admin_page/dist ./nonebot_bison/admin_page/dist
EXPOSE 8080
ENV BISON_SKIP_BROWSER_CHECK=True \
BISON_USE_BROWSER=False
RUN echo '#!/bin/bash' > /app/start.sh && \
echo 'echo "📌 Current bison Version: $(cat /app/VERSION)"' >> /app/start.sh && \
echo 'echo "🚀 Starting service..."' >> /app/start.sh && \
echo 'nb run' >> /app/start.sh && \
chmod +x /app/start.sh
CMD ["/app/start.sh"]
+2 -2
View File
@@ -1,7 +1,7 @@
from nonebot import on_request
from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.event import FriendRequestEvent, GroupRequestEvent
from nonebot.log import logger
from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.event import GroupRequestEvent, FriendRequestEvent
friend_req = on_request(priority=5)
+4 -4
View File
@@ -6,8 +6,8 @@ require("nonebot_plugin_saa")
import nonebot_plugin_saa
from . import admin_page, bootstrap, config, platform, post, scheduler, send, sub_manager, theme, types, utils
from .plugin_config import PlugConfig, plugin_config
from . import post, send, theme, types, utils, config, platform, bootstrap, scheduler, admin_page, sub_manager
__help__version__ = "0.8.2"
nonebot_plugin_saa.enable_auto_select_bot()
@@ -36,12 +36,12 @@ __all__ = [
"admin_page",
"bootstrap",
"config",
"platform",
"sub_manager",
"post",
"scheduler",
"send",
"sub_manager",
"theme",
"platform",
"types",
"utils",
"theme",
]
+5 -6
View File
@@ -2,16 +2,15 @@ import os
from pathlib import Path
from typing import TYPE_CHECKING
from nonebot import get_driver, on_command
from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.event import PrivateMessageEvent
from nonebot.log import logger
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot_bison.plugin_config import plugin_config
from nonebot import get_driver, on_command
from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.event import PrivateMessageEvent
from .api import router as api_router
from ..plugin_config import plugin_config
from .token_manager import token_manager as tm
if TYPE_CHECKING:
@@ -22,9 +21,9 @@ STATIC_PATH = (Path(__file__).parent / "dist").resolve()
def init_fastapi(driver: "Driver"):
import socketio
from fastapi.applications import FastAPI
from fastapi.staticfiles import StaticFiles
import socketio
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
socket_app = socketio.ASGIApp(sio, socketio_path="socket")
+23 -30
View File
@@ -1,39 +1,37 @@
from typing import cast
from fastapi import status
from fastapi.exceptions import HTTPException
from fastapi.param_functions import Depends
from fastapi.routing import APIRouter
from fastapi.security.oauth2 import OAuth2PasswordBearer
import nonebot
from fastapi import status
from fastapi.routing import APIRouter
from fastapi.param_functions import Depends
from fastapi.exceptions import HTTPException
from nonebot_plugin_saa import TargetQQGroup
from nonebot_plugin_saa.auto_select_bot import get_bot
from fastapi.security.oauth2 import OAuth2PasswordBearer
from nonebot_bison.apis import check_sub_target
from nonebot_bison.config import NoSuchSubscribeException, NoSuchTargetException, NoSuchUserException, config
from nonebot_bison.config.db_config import SubscribeDupException
from nonebot_bison.platform import platform_manager
from nonebot_bison.scheduler import scheduler_dict
from nonebot_bison.types import Target as T_Target
from nonebot_bison.types import WeightConfig
from nonebot_bison.utils.get_bot import get_groups
from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager, site_manager
from ..types import WeightConfig
from ..apis import check_sub_target
from .jwt import load_jwt, pack_jwt
from ..scheduler import scheduler_dict
from ..types import Target as T_Target
from ..utils.get_bot import get_groups
from ..platform import platform_manager
from .token_manager import token_manager
from ..config.db_config import SubscribeDupException
from ..utils.site import CookieClientManager, site_manager, is_cookie_client_manager
from ..config import NoSuchUserException, NoSuchTargetException, NoSuchSubscribeException, config
from .types import (
AddSubscribeReq,
Cookie,
CookieTarget,
TokenResp,
GlobalConf,
PlatformConfig,
SiteConfig,
StatusResp,
CookieTarget,
SubscribeResp,
PlatformConfig,
AddSubscribeReq,
SubscribeConfig,
SubscribeGroupDetail,
SubscribeResp,
Target,
TokenResp,
)
router = APIRouter(prefix="/api", tags=["api"])
@@ -213,7 +211,7 @@ async def update_weigth_config(platformName: str, target: str, weight_config: We
@router.get("/cookie", dependencies=[Depends(check_is_superuser)])
async def get_cookie(site_name: str | None = None, target: str | None = None) -> list[Cookie]:
async def get_cookie(site_name: str = None, target: str = None) -> list[Cookie]:
cookies_in_db = await config.get_cookie(site_name, is_anonymous=False)
return [
Cookie(
@@ -252,12 +250,7 @@ async def get_cookie_target(
cookie_targets = await config.get_cookie_target()
# TODO: filter in SQL
return [
CookieTarget(
target=Target(
platform_name=x.target.platform_name, target_name=x.target.target_name, target=x.target.target
),
cookie_id=x.cookie.id,
)
x
for x in cookie_targets
if (site_name is None or x.cookie.site_name == site_name)
and (target is None or x.target.target == target)
@@ -266,13 +259,13 @@ async def get_cookie_target(
@router.post("/cookie_target", dependencies=[Depends(check_is_superuser)])
async def add_cookie_target(platform_name: str, target: T_Target, cookie_id: int) -> StatusResp:
async def add_cookie_target(platform_name: str, target: str, cookie_id: int) -> StatusResp:
await config.add_cookie_target(target, platform_name, cookie_id)
return StatusResp(ok=True, msg="")
@router.delete("/cookie_target", dependencies=[Depends(check_is_superuser)])
async def del_cookie_target(platform_name: str, target: T_Target, cookie_id: int) -> StatusResp:
async def del_cookie_target(platform_name: str, target: str, cookie_id: int) -> StatusResp:
await config.delete_cookie_target(target, platform_name, cookie_id)
return StatusResp(ok=True, msg="")
+1 -1
View File
@@ -1,6 +1,6 @@
import datetime
import random
import string
import datetime
import jwt
+1 -1
View File
@@ -1,6 +1,6 @@
from datetime import timedelta
import random
import string
from datetime import timedelta
from expiringdictx import ExpiringDict
+1 -1
View File
@@ -60,8 +60,8 @@ class StatusResp(BaseModel):
msg: str
from datetime import datetime
from typing import Any
from datetime import datetime
from pydantic import BaseModel
+2 -2
View File
@@ -1,6 +1,6 @@
from .platform import platform_manager
from .scheduler import scheduler_dict
from .types import Target
from .scheduler import scheduler_dict
from .platform import platform_manager
async def check_sub_target(platform_name: str, target: Target):
+3 -3
View File
@@ -1,10 +1,10 @@
from nonebot.log import logger
from nonebot_plugin_datastore.db import get_engine, post_db_init, pre_db_init
from sqlalchemy import inspect, text
from sqlalchemy import text, inspect
from nonebot_plugin_datastore.db import get_engine, pre_db_init, post_db_init
from .config.config_legacy import start_up as legacy_db_startup
from .config.db_migration import data_migrate
from .scheduler.manager import init_scheduler
from .config.config_legacy import start_up as legacy_db_startup
@pre_db_init
+2 -2
View File
@@ -1,9 +1,9 @@
from typing import Literal, overload
from nonebot.compat import PYDANTIC_V2
from pydantic import BaseModel
from nonebot.compat import PYDANTIC_V2
__all__ = ("model_rebuild", "model_validator")
__all__ = ("model_validator", "model_rebuild")
if PYDANTIC_V2:
+2 -2
View File
@@ -1,4 +1,4 @@
from .db_config import config as config
from .utils import NoSuchSubscribeException as NoSuchSubscribeException
from .utils import NoSuchTargetException as NoSuchTargetException
from .utils import NoSuchUserException as NoSuchUserException
from .utils import NoSuchTargetException as NoSuchTargetException
from .utils import NoSuchSubscribeException as NoSuchSubscribeException
+8 -9
View File
@@ -1,20 +1,19 @@
from collections import defaultdict
from datetime import datetime
import json
import os
import json
from os import path
from pathlib import Path
from datetime import datetime
from collections import defaultdict
from typing import Literal, TypedDict
from nonebot.log import logger
from tinydb import Query, TinyDB
from nonebot_bison.platform import platform_manager
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.types import Target, User
from nonebot_bison.utils import Singleton
from .utils import NoSuchSubscribeException, NoSuchUserException
from ..utils import Singleton
from ..types import User, Target
from ..platform import platform_manager
from ..plugin_config import plugin_config
from .utils import NoSuchUserException, NoSuchSubscribeException
supported_target_type = platform_manager.keys()
+11 -15
View File
@@ -1,20 +1,20 @@
import asyncio
from collections import defaultdict
from collections.abc import Awaitable, Callable, Sequence
from datetime import datetime, time
from datetime import time, datetime
from collections.abc import Callable, Sequence, Awaitable
from nonebot.compat import model_dump
from nonebot_plugin_datastore import create_session
from nonebot_plugin_saa import PlatformTarget
from sqlalchemy import delete, func, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import selectinload
from sqlalchemy.exc import IntegrityError
from sqlalchemy import func, delete, select
from nonebot_plugin_saa import PlatformTarget
from nonebot_plugin_datastore import create_session
from nonebot_bison.types import Category, PlatformWeightConfigResp, Tag, TimeWeightConfig, UserSubInfo, WeightConfig
from nonebot_bison.types import Target as T_Target
from .db_model import Cookie, CookieTarget, ScheduleTimeWeight, Subscribe, Target, User
from .utils import DuplicateCookieTargetException, NoSuchTargetException
from ..types import Tag
from ..types import Target as T_Target
from .utils import NoSuchTargetException, DuplicateCookieTargetException
from .db_model import User, Cookie, Target, Subscribe, CookieTarget, ScheduleTimeWeight
from ..types import Category, UserSubInfo, WeightConfig, TimeWeightConfig, PlatformWeightConfigResp
def _get_time():
@@ -288,8 +288,6 @@ class DBConfig:
async def get_cookie_by_id(self, cookie_id: int) -> Cookie:
async with create_session() as sess:
cookie = await sess.scalar(select(Cookie).where(Cookie.id == cookie_id))
if not cookie:
raise NoSuchTargetException(f"cookie {cookie_id} not found")
return cookie
async def add_cookie(self, cookie: Cookie) -> int:
@@ -319,8 +317,6 @@ class DBConfig:
.outerjoin(CookieTarget)
.options(selectinload(Cookie.targets))
)
if not cookie:
raise NoSuchTargetException(f"cookie {cookie_id} not found")
if len(cookie.targets) > 0:
raise Exception(f"cookie {cookie.id} in use")
await sess.execute(delete(Cookie).where(Cookie.id == cookie_id))
+3 -3
View File
@@ -1,11 +1,11 @@
from nonebot.compat import model_dump
from nonebot.log import logger
from nonebot.compat import model_dump
from nonebot_plugin_datastore.db import get_engine
from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate
from sqlalchemy.ext.asyncio.session import AsyncSession
from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate
from .db_model import User, Target, Subscribe
from .config_legacy import Config, ConfigContent, drop
from .db_model import Subscribe, Target, User
async def data_migrate():
+6 -6
View File
@@ -1,15 +1,15 @@
import datetime
from pathlib import Path
from typing import Any
from pathlib import Path
from nonebot_plugin_saa import PlatformTarget
from sqlalchemy.dialects.postgresql import JSONB
from nonebot.compat import PYDANTIC_V2, ConfigDict
from nonebot_plugin_datastore import get_plugin_data
from nonebot_plugin_saa import PlatformTarget
from sqlalchemy import JSON, DateTime, ForeignKey, String, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import Mapped, relationship, mapped_column
from sqlalchemy import JSON, String, DateTime, ForeignKey, UniqueConstraint
from nonebot_bison.types import Category, Tag
from ..types import Tag, Category
Model = get_plugin_data().Model
get_plugin_data().set_migration_dir(Path(__file__).parent / "migrations")
@@ -6,8 +6,8 @@ Create Date: 2022-03-21 19:18:13.762626
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "0571870f5222"
@@ -6,8 +6,8 @@ Create Date: 2022-03-27 21:50:10.911649
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "4a46ba54a3f3"
@@ -6,8 +6,8 @@ Create Date: 2022-05-31 22:05:13.235981
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "5f3370328e44"
@@ -6,8 +6,8 @@ Create Date: 2023-03-20 00:39:30.199915
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects.postgresql import JSONB
# revision identifiers, used by Alembic.
@@ -6,8 +6,8 @@ Create Date: 2023-03-20 11:08:42.883556
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects.postgresql import JSONB
# revision identifiers, used by Alembic.
@@ -6,8 +6,8 @@ Create Date: 2023-03-20 15:38:20.220599
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "8d3863e9d74b"
@@ -6,8 +6,8 @@ Create Date: 2022-03-29 21:01:38.213153
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "a333d6224193"
@@ -6,10 +6,10 @@ Create Date: 2023-03-20 01:14:42.623789
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.ext.automap import automap_base
from alembic import op
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base
# revision identifiers, used by Alembic.
revision = "a5466912fad0"
@@ -6,8 +6,8 @@ Create Date: 2023-03-09 19:10:42.168133
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "aceef470d69c"
@@ -6,11 +6,11 @@ Create Date: 2023-03-02 14:04:16.492133
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
from sqlalchemy import select
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base
# revision identifiers, used by Alembic.
revision = "bd92923c218f"
@@ -6,8 +6,8 @@ Create Date: 2024-09-23 10:03:30.593263
"""
from alembic import op
import sqlalchemy as sa
from alembic import op
from sqlalchemy import Text
from sqlalchemy.dialects import postgresql
@@ -6,10 +6,10 @@ Create Date: 2023-08-25 00:20:51.511329
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.ext.automap import automap_base
from alembic import op
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base
# revision identifiers, used by Alembic.
revision = "f9baef347cc8"
@@ -3,4 +3,4 @@
from . import v1, v2, v3
from .base import NBESFBase
__all__ = ["NBESFBase", "v1", "v2", "v3"]
__all__ = ["v1", "v2", "v3", "NBESFBase"]
@@ -1,10 +1,10 @@
from abc import ABC
from pydantic import BaseModel
from nonebot.compat import PYDANTIC_V2, ConfigDict
from nonebot_plugin_saa.registries import AllSupportedPlatformTarget as UserInfo
from pydantic import BaseModel
from nonebot_bison.types import Category, Tag
from ....types import Tag, Category
class NBESFBase(BaseModel, ABC):
+10 -11
View File
@@ -1,18 +1,17 @@
"""nbesf is Nonebot Bison Enchangable Subscribes File! ver.1"""
from functools import partial
from typing import Any
from functools import partial
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from nonebot.log import logger
from pydantic import BaseModel
from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate
from pydantic import BaseModel, Field
from nonebot_bison.config.db_config import SubscribeDupException, config
from nonebot_bison.config.subs_io.utils import NBESFParseErr
from nonebot_bison.types import Category, Tag
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from ..utils import NBESFParseErr
from ....types import Tag, Category
from .base import NBESFBase, SubReceipt
from ...db_config import SubscribeDupException, config
# ===== nbesf 定义格式 ====== #
NBESF_VERSION = 1
@@ -80,7 +79,7 @@ class SubGroup(
"""
version: int = NBESF_VERSION
groups: list[SubPack] = Field(default_factory=list)
groups: list[SubPack] = []
# ======================= #
@@ -109,11 +108,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup):
try:
await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"}))
except SubscribeDupException:
logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在")
logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在")
except Exception as e:
logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}")
logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}")
else:
logger.success(f"添加订阅条目 {receipt!r} 成功!")
logger.success(f"添加订阅条目 {repr(receipt)} 成功!")
def nbesf_parser(raw_data: Any) -> SubGroup:
+10 -11
View File
@@ -1,18 +1,17 @@
"""nbesf is Nonebot Bison Enchangable Subscribes File! ver.2"""
from functools import partial
from typing import Any
from functools import partial
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from nonebot.log import logger
from pydantic import BaseModel
from nonebot_plugin_saa.registries import AllSupportedPlatformTarget
from pydantic import BaseModel, Field
from nonebot_bison.config.db_config import SubscribeDupException, config
from nonebot_bison.config.subs_io.utils import NBESFParseErr
from nonebot_bison.types import Category, Tag
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from ..utils import NBESFParseErr
from ....types import Tag, Category
from .base import NBESFBase, SubReceipt
from ...db_config import SubscribeDupException, config
# ===== nbesf 定义格式 ====== #
NBESF_VERSION = 2
@@ -65,7 +64,7 @@ class SubGroup(NBESFBase):
"""
version: int = NBESF_VERSION
groups: list[SubPack] = Field(default_factory=list)
groups: list[SubPack] = []
# ======================= #
@@ -86,11 +85,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup):
try:
await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"}))
except SubscribeDupException:
logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在")
logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在")
except Exception as e:
logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}")
logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}")
else:
logger.success(f"添加订阅条目 {receipt!r} 成功!")
logger.success(f"添加订阅条目 {repr(receipt)} 成功!")
def nbesf_parser(raw_data: Any) -> SubGroup:
+15 -17
View File
@@ -1,20 +1,18 @@
"""nbesf is Nonebot Bison Enchangable Subscribes File! ver.2"""
from functools import partial
from typing import Any
from functools import partial
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from nonebot.log import logger
from pydantic import BaseModel
from nonebot_plugin_saa.registries import AllSupportedPlatformTarget
from pydantic import BaseModel, Field
from nonebot_bison.config.db_config import SubscribeDupException, config
from nonebot_bison.config.db_model import Cookie as DBCookie
from nonebot_bison.config.subs_io.utils import NBESFParseErr
from nonebot_bison.types import Category, Tag
from nonebot_bison.types import Target as T_Target
from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python
from ..utils import NBESFParseErr
from ....types import Tag, Category
from .base import NBESFBase, SubReceipt
from ...db_model import Cookie as DBCookie
from ...db_config import SubscribeDupException, config
# ===== nbesf 定义格式 ====== #
NBESF_VERSION = 3
@@ -79,8 +77,8 @@ class SubGroup(NBESFBase):
"""
version: int = NBESF_VERSION
groups: list[SubPack] = Field(default_factory=list)
cookies: list[Cookie] = Field(default_factory=list)
groups: list[SubPack] = []
cookies: list[Cookie] = []
# ======================= #
@@ -102,11 +100,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup):
try:
await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"}))
except SubscribeDupException:
logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在")
logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在")
except Exception as e:
logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}")
logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}")
else:
logger.success(f"添加订阅条目 {receipt!r} 成功!")
logger.success(f"添加订阅条目 {repr(receipt)} 成功!")
async def magic_cookie_gen(nbesf_data: SubGroup):
@@ -116,11 +114,11 @@ async def magic_cookie_gen(nbesf_data: SubGroup):
new_cookie = DBCookie(**model_dump(cookie, exclude={"targets"}))
cookie_id = await config.add_cookie(new_cookie)
for target in cookie.targets:
await config.add_cookie_target(T_Target(target.target), target.platform_name, cookie_id)
await config.add_cookie_target(target.target, target.platform_name, cookie_id)
except Exception as e:
logger.error(f"!添加 Cookie 条目 {cookie!r} 失败: {e!r}")
logger.error(f"!添加 Cookie 条目 {repr(cookie)} 失败: {repr(e)}")
else:
logger.success(f"添加 Cookie 条目 {cookie!r} 成功!")
logger.success(f"添加 Cookie 条目 {repr(cookie)} 成功!")
def nbesf_parser(raw_data: Any) -> SubGroup:
+10 -11
View File
@@ -1,20 +1,19 @@
from typing import cast
from collections import defaultdict
from collections.abc import Callable
from typing import cast
from nonebot.compat import type_validate_python
from nonebot.log import logger
from nonebot_plugin_datastore.db import create_session
from nonebot_plugin_saa import PlatformTarget
from sqlalchemy import select
from sqlalchemy.orm.strategy_options import selectinload
from nonebot.log import logger
from sqlalchemy.sql.selectable import Select
from nonebot_plugin_saa import PlatformTarget
from nonebot.compat import type_validate_python
from nonebot_plugin_datastore.db import create_session
from sqlalchemy.orm.strategy_options import selectinload
from nonebot_bison.config import config
from nonebot_bison.config.db_model import Cookie, CookieTarget, Subscribe, Target, User
from .nbesf_model import NBESFBase, v1, v2, v3
from .. import config
from .utils import NBESFVerMatchErr, row2dict
from .nbesf_model import NBESFBase, v1, v2, v3
from ..db_model import User, Cookie, Target, Subscribe, CookieTarget
async def subscribes_export(selector: Callable[[Select], Select]) -> v3.SubGroup:
@@ -66,7 +65,7 @@ async def subscribes_export(selector: Callable[[Select], Select]) -> v3.SubGroup
target_payload = type_validate_python(v3.Target, cookie_target.target)
cookie_target_dict[cookie_target.cookie].append(target_payload)
def cookie_transform(cookie: Cookie, targets: list[v3.Target]) -> v3.Cookie:
def cookie_transform(cookie: Cookie, targets: [Target]) -> v3.Cookie:
cookie_dict = row2dict(cookie)
cookie_dict["tags"] = cookie.tags
cookie_dict["targets"] = targets
+2 -4
View File
@@ -1,6 +1,4 @@
from typing import Any
from sqlalchemy.orm import DeclarativeBase
from ..db_model import Model
class NBESFVerMatchErr(Exception): ...
@@ -9,7 +7,7 @@ class NBESFVerMatchErr(Exception): ...
class NBESFParseErr(Exception): ...
def row2dict(row: DeclarativeBase) -> dict[str, Any]:
def row2dict(row: Model) -> dict:
d = {}
for column in row.__table__.columns:
d[column.name] = str(getattr(row, column.name))
+3 -4
View File
@@ -1,10 +1,9 @@
from collections import defaultdict
from importlib import import_module
from pathlib import Path
from pkgutil import iter_modules
from collections import defaultdict
from importlib import import_module
from nonebot_bison.plugin_config import plugin_config
from ..plugin_config import plugin_config
from .platform import Platform, make_no_target_group
_package_dir = str(Path(__file__).resolve().parent)
+16 -17
View File
@@ -1,19 +1,18 @@
from functools import partial
import html
import re
from typing import Any, ClassVar
import html
from typing import Any
from functools import partial
from bs4 import BeautifulSoup as bs
from httpx import AsyncClient
from nonebot.compat import type_validate_python
from pydantic import BaseModel, Field
from yarl import URL
from httpx import AsyncClient
from bs4 import BeautifulSoup as bs
from pydantic import Field, BaseModel
from nonebot.compat import type_validate_python
from nonebot_bison.post import Post
from nonebot_bison.post.protocol import HTMLContentSupport
from nonebot_bison.types import Category, RawPost, Target
from nonebot_bison.utils import Site
from ..post import Post
from ..utils import Site
from ..types import Target, RawPost, Category
from ..post.protocol import HTMLContentSupport
from .platform import NewMessage, StatusChange
@@ -59,7 +58,7 @@ class ArkBulletinResponse(ArkResponseBase):
class ArknightsSite(Site):
name = "arknights"
schedule_type = "interval"
schedule_setting: ClassVar[dict] = {"seconds": 30}
schedule_setting = {"seconds": 30}
class ArknightsPost(Post, HTMLContentSupport):
@@ -96,7 +95,7 @@ class ArknightsPost(Post, HTMLContentSupport):
class Arknights(NewMessage):
categories: ClassVar[dict[Category, str]] = {1: "游戏公告"}
categories = {1: "游戏公告"}
platform_name = "arknights"
name = "明日方舟游戏信息"
enable_tag = False
@@ -158,7 +157,7 @@ class Arknights(NewMessage):
class AkVersion(StatusChange):
categories: ClassVar[dict[Category, str]] = {2: "更新信息"}
categories = {2: "更新信息"}
platform_name = "arknights"
name = "明日方舟游戏信息"
enable_tag = False
@@ -203,7 +202,7 @@ class AkVersion(StatusChange):
class MonsterSiren(NewMessage):
categories: ClassVar[dict[Category, str]] = {3: "塞壬唱片新闻"}
categories = {3: "塞壬唱片新闻"}
platform_name = "arknights"
name = "明日方舟游戏信息"
enable_tag = False
@@ -251,7 +250,7 @@ class MonsterSiren(NewMessage):
class TerraHistoricusComic(NewMessage):
categories: ClassVar[dict[Category, str]] = {4: "泰拉记事社漫画"}
categories = {4: "泰拉记事社漫画"}
platform_name = "arknights"
name = "明日方舟游戏信息"
enable_tag = False
+3 -3
View File
@@ -1,7 +1,7 @@
from .platforms import Bilibili as Bilibili
from .platforms import BilibiliBangumi as BilibiliBangumi
from .platforms import Bilibililive as Bilibililive
from .scheduler import BiliBangumiSite as BiliBangumiSite
from .scheduler import BilibiliClientManager as BilibiliClientManager
from .scheduler import BilibiliSite as BilibiliSite
from .scheduler import BililiveSite as BililiveSite
from .platforms import BilibiliBangumi as BilibiliBangumi
from .scheduler import BiliBangumiSite as BiliBangumiSite
from .scheduler import BilibiliClientManager as BilibiliClientManager
+9 -9
View File
@@ -1,22 +1,22 @@
import sys
import asyncio
from collections.abc import AsyncGenerator, Awaitable, Callable, Sequence
from collections.abc import Set as AbstractSet
from dataclasses import dataclass
import inspect
from enum import Enum
from functools import wraps
import inspect
import sys
from dataclasses import dataclass
from collections.abc import Set as AbstractSet
from collections.abc import Callable, Sequence, Awaitable, AsyncGenerator
from typing import (
TYPE_CHECKING,
Any,
Concatenate,
Generic,
NamedTuple,
ParamSpec,
TypeVar,
Protocol,
ParamSpec,
TypeAlias,
TypedDict,
TypeVar,
NamedTuple,
Concatenate,
overload,
runtime_checkable,
)
+4 -12
View File
@@ -1,7 +1,7 @@
from typing import Any, Literal, TypeAlias, TypeVar
from typing import Any, Literal, TypeVar, TypeAlias
from nonebot.compat import PYDANTIC_V2, ConfigDict
from pydantic import BaseModel
from nonebot.compat import PYDANTIC_V2, ConfigDict
from nonebot_bison.compat import model_rebuild
@@ -13,7 +13,7 @@ TBaseModel = TypeVar("TBaseModel", bound=type[BaseModel])
def model_rebuild_recurse(cls: TBaseModel) -> TBaseModel:
"""Recursively rebuild all BaseModel subclasses in the class."""
if not PYDANTIC_V2:
from inspect import getmembers, isclass
from inspect import isclass, getmembers
for _, sub_cls in getmembers(cls, lambda x: isclass(x) and issubclass(x, BaseModel)):
model_rebuild_recurse(sub_cls)
@@ -131,7 +131,7 @@ class PostAPI(APIBase):
basic: "PostAPI.Basic"
id_str: str
modules: "PostAPI.Modules"
orig: "PostAPI.Item | PostAPI.DeletedItem | None" = None
orig: "PostAPI.Item | None" = None
topic: "PostAPI.Topic | None" = None
type: DynamicType
@@ -141,14 +141,6 @@ class PostAPI(APIBase):
modules: "PostAPI.Modules"
type: Literal["DYNAMIC_TYPE_NONE"]
def to_item(self) -> "PostAPI.Item":
return PostAPI.Item(
basic=self.basic,
id_str="",
modules=self.modules,
type=self.type,
)
class Data(Base):
items: "list[PostAPI.Item | PostAPI.DeletedItem] | None" = None
+39 -55
View File
@@ -1,41 +1,40 @@
import re
import json
from copy import deepcopy
from enum import Enum, unique
import json
import re
from typing import ClassVar, NamedTuple
from typing import NamedTuple
from typing_extensions import Self
from httpx import AsyncClient
from nonebot import logger
from nonebot.compat import type_validate_json, type_validate_python
from pydantic import BaseModel, Field, ValidationError
from yarl import URL
from nonebot import logger
from httpx import AsyncClient
from pydantic import Field, BaseModel, ValidationError
from nonebot.compat import type_validate_json, type_validate_python
from nonebot_bison.compat import model_rebuild
from nonebot_bison.platform.platform import CategoryNotRecognize, CategoryNotSupport, NewMessage, StatusChange
from nonebot_bison.post.post import Post
from nonebot_bison.types import ApiError, Category, RawPost, Tag, Target
from nonebot_bison.utils import decode_unicode_escapes, text_similarity
from nonebot_bison.compat import model_rebuild
from nonebot_bison.utils import text_similarity, decode_unicode_escapes
from nonebot_bison.types import Tag, Target, RawPost, ApiError, Category
from .models import (
ArticleMajor,
CommonMajor,
CoursesMajor,
DeletedMajor,
DrawMajor,
DynamicType,
DynRawPost,
LiveMajor,
LiveRecommendMajor,
OPUSMajor,
PGCMajor,
PostAPI,
UnknownMajor,
UserAPI,
VideoMajor,
)
from .retry import ApiCode352Error, retry_for_352
from .scheduler import BiliBangumiSite, BilibiliSite, BililiveSite
from .scheduler import BilibiliSite, BililiveSite, BiliBangumiSite
from ..platform import NewMessage, StatusChange, CategoryNotSupport, CategoryNotRecognize
from .models import (
PostAPI,
UserAPI,
PGCMajor,
DrawMajor,
LiveMajor,
OPUSMajor,
DynRawPost,
VideoMajor,
CommonMajor,
DynamicType,
ArticleMajor,
CoursesMajor,
UnknownMajor,
LiveRecommendMajor,
)
class _ProcessedText(NamedTuple):
@@ -51,7 +50,7 @@ class _ParsedMojarPost(NamedTuple):
class Bilibili(NewMessage):
categories: ClassVar[dict[Category, str]] = {
categories = {
1: "一般动态",
2: "专栏文章",
3: "视频",
@@ -94,7 +93,7 @@ class Bilibili(NewMessage):
@retry_for_352
async def get_sub_list(self, target: Target) -> list[DynRawPost]:
client = await self.ctx.get_client(target)
params = {"host_mid": target, "timezone_offset": -480, "offset": "", "features": "itemOpusStyle"}
params = {"host_mid": target, "timezone_offset": -480, "offset": ""}
res = await client.get(
"https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space",
params=params,
@@ -162,6 +161,7 @@ class Bilibili(NewMessage):
return tags
def _text_process(self, dynamic: str, desc: str, title: str) -> _ProcessedText:
# 计算视频标题和视频描述相似度
title_similarity = 0.0 if len(title) == 0 or len(desc) == 0 else text_similarity(title, desc[: len(title)])
if title_similarity > 0.9:
@@ -243,13 +243,6 @@ class Bilibili(NewMessage):
pics=[courses.cover],
url=URL(courses.jump_url).with_scheme("https").human_repr(),
)
case DeletedMajor(none=none):
return _ParsedMojarPost(
title="",
content=none.tips,
pics=[],
url=None,
)
case UnknownMajor(type=unknown_type):
raise CategoryNotSupport(unknown_type)
case None: # 没有major的情况
@@ -266,13 +259,10 @@ class Bilibili(NewMessage):
parsed_raw_post = self.pre_parse_by_mojar(raw_post)
parsed_raw_repost = None
if self._do_get_category(raw_post.type) == Category(5):
match raw_post.orig:
case PostAPI.Item() as orig:
parsed_raw_repost = self.pre_parse_by_mojar(orig)
case PostAPI.DeletedItem() as orig:
parsed_raw_repost = self.pre_parse_by_mojar(orig.to_item())
case None:
logger.warning(f"转发动态{raw_post.id_str}没有原动态")
if raw_post.orig:
parsed_raw_repost = self.pre_parse_by_mojar(raw_post.orig)
else:
logger.warning(f"转发动态{raw_post.id_str}没有原动态")
post = Post(
self,
@@ -285,14 +275,8 @@ class Bilibili(NewMessage):
nickname=raw_post.modules.module_author.name,
)
if parsed_raw_repost:
match raw_post.orig:
case PostAPI.Item() as orig:
orig = orig
case PostAPI.DeletedItem() as orig:
orig = orig.to_item()
case None:
raise ValueError("转发动态没有原动态")
orig = raw_post.orig
assert orig
post.repost = Post(
self,
content=decode_unicode_escapes(parsed_raw_repost.content),
@@ -307,7 +291,7 @@ class Bilibili(NewMessage):
class Bilibililive(StatusChange):
categories: ClassVar[dict[Category, str]] = {1: "开播提醒", 2: "标题更新提醒", 3: "下播提醒"}
categories = {1: "开播提醒", 2: "标题更新提醒", 3: "下播提醒"}
platform_name = "bilibili-live"
enable_tag = False
enabled = True
@@ -457,7 +441,7 @@ class Bilibililive(StatusChange):
class BilibiliBangumi(StatusChange):
categories: ClassVar[dict[Category, str]] = {}
categories = {}
platform_name = "bilibili-bangumi"
enable_tag = False
enabled = True
+10 -9
View File
@@ -1,20 +1,20 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
import random
from enum import Enum
from functools import wraps
import random
from dataclasses import dataclass
from datetime import datetime, timedelta
from collections.abc import Callable, Awaitable
from typing_extensions import override, assert_never
from typing import TYPE_CHECKING, Generic, Literal, TypeVar
from typing_extensions import assert_never, override
from httpx import URL as HttpxURL
from nonebot.log import logger
from strenum import StrEnum
from nonebot.log import logger
from httpx import URL as HttpxURL
from nonebot_bison.types import Target
from .fsm import FSM, ActionReturn, Condition, StateGraph, Transition, reset_on_exception
from .models import DynRawPost
from .fsm import FSM, Condition, StateGraph, Transition, ActionReturn, reset_on_exception
if TYPE_CHECKING:
from .platforms import Bilibili
@@ -115,7 +115,8 @@ class RetryAddon(Generic[TBilibili]):
def record_backoff_finish_time(self):
self.backoff_finish_time = (
datetime.now() + self.backoff_timedelta * self.backoff_count**2
datetime.now()
+ self.backoff_timedelta * self.backoff_count**2
# + timedelta(seconds=random.randint(1, 60)) # jitter
)
logger.trace(f"set backoff finish time: {self.backoff_finish_time}")
+11 -11
View File
@@ -1,29 +1,29 @@
from datetime import datetime, timedelta
import json
import random
from typing import TYPE_CHECKING, ClassVar, TypeVar
from typing_extensions import override
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, TypeVar
from httpx import AsyncClient
from nonebot import logger, require
from playwright.async_api import Cookie
from nonebot_bison.config.db_model import Cookie as CookieModel
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.utils import Site, http_client
from nonebot_bison.utils.site import CookieClientManager
from ...utils.site import CookieClientManager
from ...config.db_model import Cookie as CookieModel
if TYPE_CHECKING:
from .platforms import Bilibili
if plugin_config.bison_use_browser:
require("nonebot_plugin_htmlrender")
from nonebot_plugin_htmlrender import get_browser
require("nonebot_plugin_htmlrender")
from nonebot_plugin_htmlrender import get_browser
B = TypeVar("B", bound="Bilibili")
class BilibiliClientManager(CookieClientManager):
_default_cookie_cd = timedelta(seconds=120)
async def _get_cookies(self) -> list[Cookie]:
@@ -75,7 +75,7 @@ class BilibiliClientManager(CookieClientManager):
class BilibiliSite(Site):
name = "bilibili.com"
schedule_setting: ClassVar[dict] = {"seconds": 60}
schedule_setting = {"seconds": 60}
schedule_type = "interval"
client_mgr = BilibiliClientManager
require_browser = True
@@ -83,11 +83,11 @@ class BilibiliSite(Site):
class BililiveSite(Site):
name = "live.bilibili.com"
schedule_setting: ClassVar[dict] = {"seconds": 5}
schedule_setting = {"seconds": 5}
schedule_type = "interval"
class BiliBangumiSite(Site):
name = "bilibili.com/bangumi"
schedule_setting: ClassVar[dict] = {"seconds": 30}
schedule_setting = {"seconds": 30}
schedule_type = "interval"
+7 -7
View File
@@ -1,16 +1,16 @@
from collections.abc import Callable
from datetime import timedelta
from functools import partial
from types import MappingProxyType
from typing import TypeAlias
from functools import partial
from datetime import timedelta
from types import MappingProxyType
from collections.abc import Callable
from expiringdictx import ExpiringDict, SimpleCache
from hishel import AsyncCacheTransport, AsyncInMemoryStorage, Controller
from httpx import AsyncClient, AsyncHTTPTransport
from expiringdictx import SimpleCache, ExpiringDict
from hishel import Controller, AsyncCacheTransport, AsyncInMemoryStorage
from .const import DATASOURCE_URL
from .models import CeobeSource, CeobeTarget, DataSourceResponse
from .utils import process_response
from .models import CeobeSource, CeobeTarget, DataSourceResponse
cache_transport = AsyncCacheTransport(
AsyncHTTPTransport(),
+1 -1
View File
@@ -1,4 +1,4 @@
DATASOURCE_URL = "https://server.ceobecanteen.top/api/v1/canteen/config/datasource/list"
COMB_ID_URL = "https://server.ceobecanteen.top/api/v1/canteen/user/getDatasourceComb"
COOKIE_ID_URL = "https://cdn.ceobecanteen.top/datasource-comb"
COOKIE_ID_URL = "http://cdn.ceobecanteen.top/datasource-comb"
COOKIES_URL = "https://server-cdn.ceobecanteen.top/api/v1/cdn/cookie/mainList/cookieList"
@@ -1,4 +1,4 @@
from typing import Literal, NamedTuple, TypeVar
from typing import Literal, TypeVar, NamedTuple
from pydantic import BaseModel
+14 -16
View File
@@ -1,23 +1,23 @@
from collections import defaultdict
from datetime import timedelta
from typing import ParamSpec
from functools import partial
from typing import ClassVar, ParamSpec
from datetime import timedelta
from collections import defaultdict
from httpx import AsyncClient
from nonebot import logger, require
from rapidfuzz import fuzz, process
from nonebot_bison.platform.platform import NewMessage
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.post import Post
from nonebot_bison.types import Category, RawPost, Target
from nonebot_bison.utils import ClientManager, Site, capture_html
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.types import Target, RawPost, Category
from nonebot_bison.utils import Site, ClientManager, capture_html
from .cache import CeobeCache, CeobeClient, CeobeDataSourceCache
from .const import COMB_ID_URL, COOKIE_ID_URL, COOKIES_URL
from .exception import CeobeSnapshotFailed, CeobeSnapshotSkip
from .models import CeobeCookie, CeobeImage, CeobeTextPic, CombIdResponse, CookieIdResponse, CookiesResponse
from ..platform import NewMessage
from .utils import process_response
from .const import COMB_ID_URL, COOKIES_URL, COOKIE_ID_URL
from .exception import CeobeSnapshotSkip, CeobeSnapshotFailed
from .cache import CeobeCache, CeobeClient, CeobeDataSourceCache
from .models import CeobeImage, CeobeCookie, CeobeTextPic, CombIdResponse, CookiesResponse, CookieIdResponse
P = ParamSpec("P")
@@ -49,7 +49,7 @@ class CeobeCanteenSite(Site):
name = "ceobe_canteen"
schedule_type = "interval"
# lwt の 推荐间隔
schedule_setting: ClassVar[dict] = {"seconds": 15}
schedule_setting = {"seconds": 15}
client_mgr = CeobeCanteenClientManager
@@ -64,7 +64,7 @@ class CeobeCanteen(NewMessage):
use_batch: bool = True
default_theme: str = "ceobecanteen"
categories: ClassVar[dict[Category, str]] = {1: "普通", 2: "转发"}
categories: dict[Category, str] = {1: "普通", 2: "转发"}
data_source_cache = CeobeDataSourceCache()
@@ -213,9 +213,7 @@ class CeobeCanteen(NewMessage):
logger.debug(f"snapshot official website url: {url}")
# /html/body/div[1]/div[1]/div/div[1]/div[1]/div
snapshot_selector = (
"html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div"
)
snapshot_selector = "html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div" # noqa: E501
# /html/body/div[1]/div[1]/div/div[1]/div[1]/div/div[4]/div/div/div
calculate_selector = "html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(4) > div > div > div" # noqa: E501
viewport = {"width": 1024, "height": 19990}
+1 -1
View File
@@ -3,7 +3,7 @@ from nonebot import logger
from nonebot.compat import type_validate_python
from .exception import CeobeResponseError
from .models import CookieIdResponse, ResponseModel
from .models import ResponseModel, CookieIdResponse
def process_response(response: Response, parse_model: type[ResponseModel]) -> ResponseModel:
+5 -6
View File
@@ -1,16 +1,15 @@
from typing import Any, ClassVar
from typing import Any
from httpx import AsyncClient
from nonebot_bison.post import Post
from nonebot_bison.types import RawPost, Target
from nonebot_bison.utils import anonymous_site
from ..post import Post
from .platform import NewMessage
from ..utils import anonymous_site
from ..types import Target, RawPost
class FF14(NewMessage):
categories: ClassVar[dict] = {}
categories = {}
platform_name = "ff14"
name = "最终幻想XIV官方公告"
enable_tag = False
+7 -8
View File
@@ -1,23 +1,22 @@
import re
from typing import Any, ClassVar
from typing import Any
from httpx import AsyncClient
from nonebot_bison.post import Post
from nonebot_bison.types import ApiError, Category, RawPost, Target
from nonebot_bison.utils import Site
from ..post import Post
from ..utils import Site
from .platform import NewMessage
from ..types import Target, RawPost, ApiError
class NcmSite(Site):
name = "music.163.com"
schedule_type = "interval"
schedule_setting: ClassVar[dict] = {"minutes": 1}
schedule_setting = {"minutes": 1}
class NcmArtist(NewMessage):
categories: ClassVar[dict[Category, str]] = {}
categories = {}
platform_name = "ncm-artist"
enable_tag = False
enabled = True
@@ -74,7 +73,7 @@ class NcmArtist(NewMessage):
class NcmRadio(NewMessage):
categories: ClassVar[dict[Category, str]] = {}
categories = {}
platform_name = "ncm-radio"
enable_tag = False
enabled = True
+10 -10
View File
@@ -1,22 +1,22 @@
from abc import ABC, abstractmethod
from collections import defaultdict
from collections.abc import Awaitable, Callable, Collection
from dataclasses import dataclass
import json
import ssl
import json
import time
import typing
from typing import Any, ParamSpec, TypeVar
from dataclasses import dataclass
from abc import ABC, abstractmethod
from collections import defaultdict
from typing import Any, TypeVar, ParamSpec
from collections.abc import Callable, Awaitable, Collection
import httpx
from httpx import AsyncClient
from nonebot.log import logger
from nonebot_plugin_saa import PlatformTarget
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.post import Post
from nonebot_bison.types import Category, RawPost, SubUnit, Tag, Target
from nonebot_bison.utils import ProcessContext, Site
from ..post import Post
from ..utils import Site, ProcessContext
from ..plugin_config import plugin_config
from ..types import Tag, Target, RawPost, SubUnit, Category
class CategoryNotSupport(Exception):
+10 -10
View File
@@ -1,27 +1,27 @@
import calendar
import time
from typing import Any, ClassVar
import calendar
from typing import Any
from bs4 import BeautifulSoup as bs
import feedparser
from httpx import AsyncClient
from bs4 import BeautifulSoup as bs
from nonebot_bison.post import Post
from nonebot_bison.types import Category, RawPost, Target
from nonebot_bison.utils import text_similarity
from nonebot_bison.utils.site import CookieClientManager, Site
from ..post import Post
from .platform import NewMessage
from ..types import Target, RawPost
from ..utils import text_similarity
from ..utils.site import Site, CookieClientManager
class RssSite(Site):
name = "rss"
schedule_type = "interval"
schedule_setting: ClassVar[dict] = {"seconds": 30}
schedule_setting = {"seconds": 30}
client_mgr = CookieClientManager.from_name(name)
class RssPost(Post):
async def get_plain_content(self) -> str:
soup = bs(self.content, "html.parser")
@@ -38,7 +38,7 @@ class RssPost(Post):
class Rss(NewMessage):
categories: ClassVar[dict[Category, str]] = {}
categories = {}
enable_tag = False
platform_name = "rss"
name = "Rss"
+14 -15
View File
@@ -1,22 +1,21 @@
from datetime import datetime
import json
import re
from typing import Any, ClassVar
from typing_extensions import override
import json
from typing import Any
from datetime import datetime
from urllib.parse import unquote
from typing_extensions import override
from bs4 import BeautifulSoup as bs
from httpx import AsyncClient
from lxml.etree import HTML
from nonebot.log import logger
from yarl import URL
from lxml.etree import HTML
from httpx import AsyncClient
from nonebot.log import logger
from bs4 import BeautifulSoup as bs
from nonebot_bison.post import Post
from nonebot_bison.types import ApiError, Category, RawPost, Tag, Target
from nonebot_bison.utils import http_client, text_fletten
from nonebot_bison.utils.site import CookieClientManager, Site
from ..post import Post
from .platform import NewMessage
from ..utils import http_client, text_fletten
from ..utils.site import Site, CookieClientManager
from ..types import Tag, Target, RawPost, ApiError, Category
_HEADER = {
"accept": (
@@ -60,12 +59,12 @@ class WeiboClientManager(CookieClientManager):
class WeiboSite(Site):
name = "weibo.com"
schedule_type = "interval"
schedule_setting: ClassVar[dict] = {"seconds": 3}
schedule_setting = {"seconds": 3}
client_mgr = WeiboClientManager
class Weibo(NewMessage):
categories: ClassVar[dict[Category, str]] = {
categories = {
1: "转发",
2: "视频",
3: "图文",
+3 -3
View File
@@ -1,8 +1,8 @@
import nonebot
from nonebot import get_plugin_config
from nonebot.compat import PYDANTIC_V2, ConfigDict
from pydantic import BaseModel, Field
from yarl import URL
from nonebot import get_plugin_config
from pydantic import Field, BaseModel
from nonebot.compat import PYDANTIC_V2, ConfigDict
global_config = nonebot.get_driver().config
PlatformName = str
+4 -4
View File
@@ -1,10 +1,10 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from abc import ABC, abstractmethod
from nonebot_plugin_saa import MessageFactory, MessageSegmentFactory, Text
from nonebot_plugin_saa import Text, MessageFactory, MessageSegmentFactory
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.utils import text_to_image
from ..utils import text_to_image
from ..plugin_config import plugin_config
@dataclass(kw_only=True)
+7 -9
View File
@@ -1,22 +1,20 @@
from collections.abc import Sequence
from dataclasses import dataclass, fields
import reprlib
from io import BytesIO
from pathlib import Path
import reprlib
from typing import TYPE_CHECKING
from dataclasses import fields, dataclass
from nonebot.log import logger
from nonebot_plugin_saa import MessageSegmentFactory
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.theme import theme_manager
from nonebot_bison.theme.types import ThemeRenderError, ThemeRenderUnsupportError
from ..theme import theme_manager
from .abstract_post import AbstractPost
from ..plugin_config import plugin_config
from .protocol import PlainContentSupport
from ..theme.types import ThemeRenderError, ThemeRenderUnsupportError
if TYPE_CHECKING:
from nonebot_bison.platform import Platform
from ..platform import Platform
@dataclass
@@ -32,7 +30,7 @@ class Post(AbstractPost, PlainContentSupport):
"""文本内容"""
title: str | None = None
"""标题"""
images: Sequence[str | bytes | Path | BytesIO] | None = None
images: list[str | bytes | Path | BytesIO] | None = None
"""图片列表"""
timestamp: float | None = None
"""发布/获取时间戳, 秒"""
+2 -2
View File
@@ -1,3 +1,3 @@
from .manager import handle_delete_target, handle_insert_new_target, init_scheduler, scheduler_dict
from .manager import init_scheduler, scheduler_dict, handle_delete_target, handle_insert_new_target
__all__ = ["handle_delete_target", "handle_insert_new_target", "init_scheduler", "scheduler_dict"]
__all__ = ["init_scheduler", "handle_delete_target", "handle_insert_new_target", "scheduler_dict"]
+7 -8
View File
@@ -2,15 +2,14 @@ from typing import cast
from nonebot.log import logger
from nonebot_bison.config import config
from nonebot_bison.config.db_model import Target
from nonebot_bison.platform import platform_manager
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.types import Target as T_Target
from nonebot_bison.utils import Site
from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager
from ..utils import Site
from ..config import config
from .scheduler import Scheduler
from ..config.db_model import Target
from ..types import Target as T_Target
from ..platform import platform_manager
from ..plugin_config import plugin_config
from ..utils.site import CookieClientManager, is_cookie_client_manager
scheduler_dict: dict[type[Site], Scheduler] = {}
+9 -7
View File
@@ -1,16 +1,18 @@
from collections import defaultdict
from dataclasses import dataclass
from collections import defaultdict
from nonebot.log import logger
from nonebot_plugin_apscheduler import scheduler
from nonebot_plugin_saa.utils.exceptions import NoBotFound
from nonebot_bison.config import config
from nonebot_bison.platform import platform_manager
from nonebot_bison.send import send_msgs
from nonebot_bison.types import SubUnit, Target
from nonebot_bison.utils import ClientManager, ProcessContext, Site
from nonebot_bison.utils.site import SkipRequestException
from nonebot_bison.utils import ClientManager
from ..config import config
from ..send import send_msgs
from ..types import Target, SubUnit
from ..platform import platform_manager
from ..utils import Site, ProcessContext
from ..utils.site import SkipRequestException
@dataclass
+13 -14
View File
@@ -1,26 +1,25 @@
from collections.abc import Callable, Coroutine
from functools import partial, wraps
import importlib
import json
from pathlib import Path
import time
import importlib
from pathlib import Path
from types import ModuleType
from typing import Any, TypeVar
from functools import wraps, partial
from collections.abc import Callable, Coroutine
from anyio import open_file
from nonebot.compat import model_dump
from nonebot.log import logger
from nonebot.compat import model_dump
from nonebot_bison.config.subs_io import subscribes_export, subscribes_import
from nonebot_bison.config.subs_io.nbesf_model import v1, v2, v3
from nonebot_bison.scheduler.manager import init_scheduler
from ..scheduler.manager import init_scheduler
from ..config.subs_io.nbesf_model import v1, v2, v3
from ..config.subs_io import subscribes_export, subscribes_import
try:
from typing_extensions import ParamSpec
import anyio
from anyio import from_thread, to_thread
import click
from anyio import to_thread, from_thread
except ImportError as e: # pragma: no cover
raise ImportError("请使用 `pip install nonebot-bison[cli]` 安装所需依赖") from e
@@ -84,7 +83,7 @@ async def subs_export(path: Path, format: str):
export_file = path / f"bison_subscribes_export_{int(time.time())}.{format}"
logger.info("正在获取订阅信息...")
export_data: v3.SubGroup = await subscribes_export(lambda x: x)
export_data: v2.SubGroup = await subscribes_export(lambda x: x)
with export_file.open("w", encoding="utf-8") as f:
match format:
@@ -128,18 +127,18 @@ async def subs_import(path: str, format: str):
import_file_path = Path(path)
assert import_file_path.is_file(), "该路径不是文件!"
async with await open_file(import_file_path, "r", encoding="utf-8") as f:
with import_file_path.open("r", encoding="utf-8") as f:
match format:
case "yaml" | "yml":
logger.info("正在从yaml导入...")
pyyaml = import_yaml_module()
import_items = pyyaml.safe_load(await f.read())
import_items = pyyaml.safe_load(f)
case "json":
logger.info("正在从json导入...")
import_items = json.loads(await f.read())
import_items = json.load(f)
case _:
raise click.BadParameter(message=f"不支持的导入格式: {format}")
+3 -7
View File
@@ -1,10 +1,10 @@
import asyncio
from collections import deque
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.log import logger
from nonebot_plugin_saa import AggregatedMessageFactory, MessageFactory, PlatformTarget
from nonebot_plugin_saa.auto_select_bot import refresh_bots
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot_plugin_saa import MessageFactory, PlatformTarget, AggregatedMessageFactory
from .plugin_config import plugin_config
@@ -14,8 +14,6 @@ QUEUE: deque[tuple[PlatformTarget, Sendable, int]] = deque()
MESSGE_SEND_INTERVAL = 1.5
_MESSAGE_DISPATCH_TASKS: set[asyncio.Task] = set()
async def _do_send(send_target: PlatformTarget, msg: Sendable):
try:
@@ -61,9 +59,7 @@ async def _send_msgs_dispatch(send_target: PlatformTarget, msg: Sendable):
QUEUE.append((send_target, msg, plugin_config.bison_resend_times))
# len(QUEUE) before append was 0
if len(QUEUE) == 1:
task = asyncio.create_task(do_send_msgs())
_MESSAGE_DISPATCH_TASKS.add(task)
task.add_done_callback(_MESSAGE_DISPATCH_TASKS.discard)
asyncio.create_task(do_send_msgs())
else:
await _do_send(send_target, msg)
+18 -23
View File
@@ -2,25 +2,23 @@ import asyncio
from datetime import datetime
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.rule import Rule, to_me
from nonebot.permission import SUPERUSER
from nonebot_plugin_saa import TargetQQGroup
from nonebot.params import ArgStr, ArgPlainText
from nonebot.adapters import Bot, MessageTemplate
from nonebot.adapters.onebot.v11.event import PrivateMessageEvent
from nonebot.matcher import Matcher
from nonebot.params import ArgPlainText, ArgStr
from nonebot.permission import SUPERUSER
from nonebot.rule import Rule, to_me
from nonebot.typing import T_State
from nonebot_plugin_saa import TargetQQGroup
from .add_cookie import do_add_cookie
from .add_cookie_target import do_add_cookie_target
from .add_sub import do_add_sub
from .del_cookie import do_del_cookie
from .del_cookie_target import do_del_cookie_target
from .del_sub import do_del_sub
from .query_sub import do_query_sub
from .utils import admin_permission, common_platform, configurable_to_me, gen_handle_cancel, set_target_user_info
_COMMAND_DISPATCH_TASKS: set[asyncio.Task] = set()
from .add_cookie import do_add_cookie
from .del_cookie import do_del_cookie
from .add_cookie_target import do_add_cookie_target
from .del_cookie_target import do_del_cookie_target
from .utils import common_platform, admin_permission, gen_handle_cancel, configurable_to_me, set_target_user_info
add_sub_matcher = on_command(
"添加订阅",
@@ -151,10 +149,7 @@ async def do_dispatch_command(
else:
do_del_sub(new_matcher)
new_matcher_ins = new_matcher()
task = asyncio.create_task(new_matcher_ins.run(bot, event, state))
_COMMAND_DISPATCH_TASKS.add(task)
task.add_done_callback(_COMMAND_DISPATCH_TASKS.discard)
asyncio.create_task(new_matcher_ins.run(bot, event, state))
no_permission_matcher = on_command(
@@ -172,14 +167,14 @@ async def send_no_permission():
__all__ = [
"add_cookie_matcher",
"add_cookie_target_matcher",
"add_sub_matcher",
"common_platform",
"del_cookie_matcher",
"del_cookie_target_matcher",
"add_sub_matcher",
"query_sub_matcher",
"del_sub_matcher",
"group_manage_matcher",
"no_permission_matcher",
"query_sub_matcher",
"add_cookie_matcher",
"add_cookie_target_matcher",
"del_cookie_target_matcher",
"del_cookie_matcher",
]
+7 -8
View File
@@ -1,17 +1,16 @@
from json import JSONDecodeError
from typing import cast
from json import JSONDecodeError
from nonebot.adapters import Message, MessageTemplate
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.log import logger
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import Arg, ArgPlainText
from nonebot.typing import T_State
from nonebot_bison.platform import platform_manager
from nonebot_bison.scheduler import scheduler_dict
from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.adapters import Message, MessageTemplate
from ..scheduler import scheduler_dict
from ..platform import platform_manager
from ..utils.site import CookieClientManager, is_cookie_client_manager
from .utils import common_platform, gen_handle_cancel, only_allow_private
+12 -10
View File
@@ -1,15 +1,14 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.internal.adapter import MessageTemplate
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import ArgPlainText
from nonebot.typing import T_State
from nonebot_plugin_saa import MessageFactory
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.internal.adapter import MessageTemplate
from nonebot_bison.config import config
from nonebot_bison.platform import platform_manager
from nonebot_bison.utils import parse_text
from .utils import gen_handle_cancel, generate_sub_list_text, only_allow_private
from ..config import config
from ..utils import parse_text
from ..platform import platform_manager
from .utils import gen_handle_cancel, only_allow_private, generate_sub_list_text
def do_add_cookie_target(add_cookie_target_matcher: type[Matcher]):
@@ -27,13 +26,15 @@ def do_add_cookie_target(add_cookie_target_matcher: type[Matcher]):
@add_cookie_target_matcher.got("target_idx", parameterless=[handle_cancel])
async def got_target_idx(state: T_State, target_idx: str = ArgPlainText()):
try:
state["target"] = state["sub_table"][int(target_idx)]
target_idx = int(target_idx)
state["target"] = state["sub_table"][target_idx]
state["site"] = platform_manager[state["target"]["platform_name"]].site
except Exception:
await add_cookie_target_matcher.reject("序号错误")
@add_cookie_target_matcher.handle()
async def init_promote_cookie(state: T_State):
# 获取 site 的所有用户 cookie,再排除掉已经关联的 cookie,剩下的就是可以关联的 cookie
cookies = await config.get_cookie(site_name=state["site"].name, is_anonymous=False)
associated_cookies = await config.get_cookie(
@@ -56,7 +57,8 @@ def do_add_cookie_target(add_cookie_target_matcher: type[Matcher]):
@add_cookie_target_matcher.got("cookie_idx", MessageTemplate("{_prompt}"), [handle_cancel])
async def got_cookie_idx(state: T_State, cookie_idx: str = ArgPlainText()):
try:
state["cookie"] = state["cookies"][int(cookie_idx) - 1]
cookie_idx = int(cookie_idx)
state["cookie"] = state["cookies"][cookie_idx - 1]
except Exception:
await add_cookie_target_matcher.reject("序号错误")
+8 -9
View File
@@ -1,18 +1,17 @@
import contextlib
from nonebot.adapters import Message, MessageTemplate
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import Arg, ArgPlainText
from nonebot.typing import T_State
from nonebot_plugin_saa import PlatformTarget, SupportedAdapters, Text
from nonebot_bison.apis import check_sub_target
from nonebot_bison.config import config
from nonebot_bison.config.db_config import SubscribeDupException
from nonebot_bison.platform import Platform, platform_manager, unavailable_paltforms
from nonebot_bison.types import Target
from nonebot.adapters import Message, MessageTemplate
from nonebot_plugin_saa import Text, PlatformTarget, SupportedAdapters
from ..types import Target
from ..config import config
from ..apis import check_sub_target
from ..config.db_config import SubscribeDupException
from .utils import common_platform, ensure_user_info, gen_handle_cancel
from ..platform import Platform, platform_manager, unavailable_paltforms
def do_add_sub(add_sub: type[Matcher]):
+4 -5
View File
@@ -1,12 +1,11 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import EventPlainText
from nonebot.typing import T_State
from nonebot_plugin_saa import MessageFactory
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot_bison.config import config
from nonebot_bison.utils import parse_text
from ..config import config
from ..utils import parse_text
from .utils import gen_handle_cancel, only_allow_private
@@ -1,12 +1,11 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import EventPlainText
from nonebot.typing import T_State
from nonebot_plugin_saa import MessageFactory
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot_bison.config import config
from nonebot_bison.utils import parse_text
from ..config import config
from ..utils import parse_text
from .utils import gen_handle_cancel, only_allow_private
+5 -6
View File
@@ -1,13 +1,12 @@
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.params import Arg, EventPlainText
from nonebot.typing import T_State
from nonebot_plugin_saa import MessageFactory, PlatformTarget
from nonebot_bison.config import config
from nonebot_bison.platform import platform_manager
from nonebot_bison.types import Category
from nonebot_bison.utils import parse_text
from ..config import config
from ..types import Category
from ..utils import parse_text
from ..platform import platform_manager
from .utils import ensure_user_info, gen_handle_cancel
+5 -6
View File
@@ -1,13 +1,12 @@
from nonebot.matcher import Matcher
from nonebot.params import Arg
from nonebot.matcher import Matcher
from nonebot_plugin_saa import MessageFactory, PlatformTarget
from nonebot_bison.config import config
from nonebot_bison.platform import platform_manager
from nonebot_bison.types import Category
from nonebot_bison.utils import parse_text
from ..config import config
from ..types import Category
from ..utils import parse_text
from .utils import ensure_user_info
from ..platform import platform_manager
def do_query_sub(query_sub: type[Matcher]):
+14 -14
View File
@@ -1,22 +1,21 @@
import contextlib
from typing import Annotated
from itertools import groupby
from operator import attrgetter
from typing import Annotated
from nonebot.adapters import Event
from nonebot.matcher import Matcher
from nonebot.params import Depends, EventPlainText, EventToMe
from nonebot.permission import SUPERUSER
from nonebot.rule import Rule
from nonebot.adapters import Event
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.params import Depends, EventToMe, EventPlainText
from nonebot_plugin_saa import PlatformTarget, extract_target
from nonebot_bison.config import config
from nonebot_bison.platform import platform_manager
from nonebot_bison.plugin_config import plugin_config
from nonebot_bison.types import Category
from nonebot_bison.types import Target as T_Target
from nonebot_bison.utils.site import is_cookie_client_manager
from ..config import config
from ..types import Category
from ..platform import platform_manager
from ..plugin_config import plugin_config
from ..utils.site import is_cookie_client_manager
def _configurable_to_me(to_me: bool = EventToMe()):
@@ -89,7 +88,7 @@ async def generate_sub_list_text(
sub_list = [
sub
for sub in sub_list
if is_cookie_client_manager(platform_manager[sub.target.platform_name].site.client_mgr)
if is_cookie_client_manager(platform_manager.get(sub.target.platform_name).site.client_mgr)
]
if not sub_list:
await matcher.finish("暂无已订阅账号\n请使用“添加订阅”命令添加订阅")
@@ -110,7 +109,7 @@ async def generate_sub_list_text(
res += " {}".format(", ".join(sub.tags)) + "\n"
if is_show_cookie:
target_cookies = await config.get_cookie(
target=T_Target(sub.target.target), site_name=platform.site.name, is_anonymous=False
target=sub.target.target, site_name=platform.site.name, is_anonymous=False
)
if target_cookies:
res += " 关联的 Cookie\n"
@@ -127,5 +126,6 @@ async def only_allow_private(
event: Event,
matcher: type[Matcher],
):
if not (hasattr(event, "message_type") and getattr(event, "message_type") == "private"):
# if not issubclass(PrivateMessageEvent, event.__class__):
if event.message_type != "private":
await matcher.finish("请在私聊中使用此命令")
+3 -2
View File
@@ -1,9 +1,10 @@
from importlib import import_module
from pathlib import Path
from pkgutil import iter_modules
from importlib import import_module
from .types import Theme
from .registry import theme_manager
from .types import Theme, ThemeRegistrationError
from .types import ThemeRegistrationError
from .types import ThemeRenderError as ThemeRenderError
from .types import ThemeRenderUnsupportError as ThemeRenderUnsupportError
+2 -5
View File
@@ -1,14 +1,11 @@
from typing import ClassVar
from nonebot import logger
from nonebot_bison.plugin_config import plugin_config
from ..plugin_config import plugin_config
from .types import Theme, ThemeRegistrationError
class ThemeManager:
__themes: ClassVar[dict[str, Theme]] = {}
__themes: dict[str, Theme] = {}
def register(self, theme: Theme):
logger.trace(f"Registering theme: {theme}")
@@ -1,13 +1,13 @@
from dataclasses import dataclass
from io import BytesIO
from pathlib import Path
from dataclasses import dataclass
from typing import TYPE_CHECKING, Literal
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError
from nonebot_bison.theme.utils import web_embed_image
from nonebot_bison.utils import text_fletten
from nonebot_bison.theme.utils import web_embed_image
from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError
if TYPE_CHECKING:
from nonebot_bison.platform.arknights import ArknightsPost
+3 -4
View File
@@ -1,12 +1,11 @@
from collections.abc import Sequence
from io import BytesIO
from pathlib import Path
from typing import TYPE_CHECKING, Literal
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.theme import Theme
from nonebot_bison.utils import is_pics_mergable, pic_merge
from nonebot_bison.utils import pic_merge, is_pics_mergable
if TYPE_CHECKING:
from nonebot_bison.post import Post
@@ -51,7 +50,7 @@ class BasicTheme(Theme):
client = await post.platform.ctx.get_client_for_static()
msgs: list[MessageSegmentFactory] = [Text(text)]
pics_group: list[Sequence[str | bytes | Path | BytesIO]] = []
pics_group: list[list[str | bytes | Path | BytesIO]] = []
if post.images:
pics_group.append(post.images)
if rp and rp.images:
+2 -2
View File
@@ -1,9 +1,9 @@
from typing import TYPE_CHECKING, Literal
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.utils import pic_merge, is_pics_mergable
from nonebot_bison.theme import Theme, ThemeRenderUnsupportError
from nonebot_bison.utils import is_pics_mergable, pic_merge
if TYPE_CHECKING:
from nonebot_bison.post import Post
@@ -1,20 +1,19 @@
from collections.abc import Sequence
from datetime import datetime
from io import BytesIO
from pathlib import Path
from datetime import datetime
from typing import TYPE_CHECKING, Literal
from httpx import AsyncClient
import jinja2
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from PIL import Image as PILImage
from pydantic import BaseModel
from yarl import URL
from httpx import AsyncClient
from pydantic import BaseModel
from PIL import Image as PILImage
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.compat import model_validator
from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError
from nonebot_bison.utils import pic_merge, is_pics_mergable
from nonebot_bison.theme.utils import convert_to_qr, web_embed_image
from nonebot_bison.utils import is_pics_mergable, pic_merge
from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError
if TYPE_CHECKING:
from nonebot_bison.post import Post
@@ -123,7 +122,7 @@ class CeobeCanteenTheme(Theme):
@staticmethod
async def merge_pics(
images: Sequence[str | bytes | Path | BytesIO],
images: list[str | bytes | Path | BytesIO],
client: AsyncClient,
) -> list[str | bytes | Path | BytesIO]:
if is_pics_mergable(images):
@@ -225,7 +224,7 @@ class CeobeCanteenTheme(Theme):
text += f"详情: {post.url}"
msgs.append(Text(text))
pics_group: list[Sequence[str | bytes | Path | BytesIO]] = []
pics_group: list[list[str | bytes | Path | BytesIO]] = []
if post.images:
pics_group.append(post.images)
if post.repost and post.repost.images:
+8 -6
View File
@@ -1,13 +1,12 @@
from collections.abc import Sequence
from io import BytesIO
from pathlib import Path
from typing import TYPE_CHECKING, Literal
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.post.protocol import HTMLContentSupport
from nonebot_bison.theme import Theme, ThemeRenderError
from nonebot_bison.utils import is_pics_mergable, pic_merge
from nonebot_bison.post.protocol import HTMLContentSupport
from nonebot_bison.utils import pic_merge, is_pics_mergable
if TYPE_CHECKING:
from nonebot_bison.post import Post
@@ -32,6 +31,7 @@ class Ht2iTheme(Theme):
raise ThemeRenderError(f"渲染文本失败: {e}")
async def render(self, post: "Post"):
md_text = ""
md_text += f"## {post.title}\n\n" if post.title else ""
@@ -50,7 +50,9 @@ class Ht2iTheme(Theme):
else:
rp_content = await rp.get_content()
md_text += "> \n> " + rp_content if len(rp_content) < 500 else f"{rp_content[:500]}..." + " \n"
md_text += (
"> \n> " + rp_content if len(rp_content) < 500 else f"{rp_content[:500]}..." + " \n" # noqa: E501
) # noqa: E501
md_text += "\n\n"
md_text += f"###### 来源: {post.platform.name} {post.nickname or ''}\n"
@@ -66,7 +68,7 @@ class Ht2iTheme(Theme):
if urls:
msgs.append(Text("\n".join(urls)))
pics_group: list[Sequence[str | bytes | Path | BytesIO]] = []
pics_group: list[list[str | bytes | Path | BytesIO]] = []
if post.images:
pics_group.append(post.images)
if rp and rp.images:
+4 -4
View File
@@ -1,14 +1,14 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
from abc import ABC, abstractmethod
from nonebot import logger, require
from nonebot_plugin_saa import MessageSegmentFactory
from pydantic import BaseModel, PrivateAttr
from nonebot_plugin_saa import MessageSegmentFactory
from nonebot_bison.plugin_config import plugin_config
from ..plugin_config import plugin_config
if TYPE_CHECKING:
from nonebot_bison.post.abstract_post import AbstractPost
from ..post.abstract_post import AbstractPost
class Theme(ABC, BaseModel):
+2 -2
View File
@@ -1,10 +1,10 @@
from base64 import b64encode
from io import BytesIO
from pathlib import Path
from base64 import b64encode
from qrcode import constants
from qrcode.image.pil import PilImage
from qrcode.main import QRCode
from qrcode.image.pil import PilImage
def convert_to_qr(data: str, **kwarg) -> bytes:
+3 -3
View File
@@ -1,10 +1,10 @@
from dataclasses import dataclass
from datetime import time
from typing import Any, Literal, NamedTuple, NewType
from dataclasses import dataclass
from typing import Any, Literal, NewType, NamedTuple
from httpx import URL
from nonebot_plugin_saa import PlatformTarget as SendTarget
from pydantic import BaseModel
from nonebot_plugin_saa import PlatformTarget as SendTarget
RawPost = Any
Target = NewType("Target", str)
+13 -15
View File
@@ -1,31 +1,29 @@
import difflib
import re
import sys
from typing import Any, ClassVar
import difflib
from bs4 import BeautifulSoup as bs
import nonebot
from nonebot.log import default_format, logger
from nonebot.plugin import require
from nonebot_plugin_saa import Image, MessageSegmentFactory, Text
from bs4 import BeautifulSoup as bs
from nonebot.log import logger, default_format
from nonebot_plugin_saa import Text, Image, MessageSegmentFactory
from nonebot_bison.plugin_config import plugin_config
from .context import ProcessContext as ProcessContext
from .site import Site as Site
from ..plugin_config import plugin_config
from .image import pic_merge as pic_merge
from .http import http_client as http_client
from .image import capture_html as capture_html
from .image import is_pics_mergable as is_pics_mergable
from .image import pic_merge as pic_merge
from .image import pic_url_to_image as pic_url_to_image
from .image import text_to_image as text_to_image
from .site import ClientManager as ClientManager
from .site import DefaultClientManager as DefaultClientManager
from .site import Site as Site
from .image import text_to_image as text_to_image
from .site import anonymous_site as anonymous_site
from .context import ProcessContext as ProcessContext
from .image import is_pics_mergable as is_pics_mergable
from .image import pic_url_to_image as pic_url_to_image
from .site import DefaultClientManager as DefaultClientManager
class Singleton(type):
_instances: ClassVar[dict[Any, Any]] = {}
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
+1 -1
View File
@@ -1,6 +1,6 @@
from base64 import b64encode
from httpx import AsyncClient, Response
from httpx import Response, AsyncClient
from nonebot_bison.types import Target

Some files were not shown because too many files have changed in this diff Show More