Merge branch 'main' into feature/pyright-check

This commit is contained in:
HibiKier 2025-03-16 21:22:52 +08:00 committed by GitHub
commit 5ceeaabf8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 1617 additions and 778 deletions

View File

@ -1,8 +1,21 @@
name: Bug 反馈 name: Bug 反馈
title: "Bug: 出现异常" title: "Bug: "
description: 提交 Bug 反馈以帮助我们改进代码 description: 提交 Bug 反馈以帮助我们改进代码
labels: ["bug"] labels: [ "bug" ]
body: body:
- type: checkboxes
id: checklist
attributes:
label: 提交前检查项
description: 在提交问题之前,请确认以下事项:
options:
- label: 我已搜索相关的 issue但没有找到类似的问题
required: true
- label: 我已更新到最新版本(包括但不限于真寻本体,插件以及相关依赖),问题仍然存在
required: true
- label: 我已仔细阅读文档,确认我的配置正确
required: true
- type: dropdown - type: dropdown
id: env-os id: env-os
attributes: attributes:

View File

@ -1,7 +1,7 @@
name: 功能建议 name: 功能建议
title: "Feature: 功能描述" title: "Feature: 功能描述"
description: 提出关于项目新功能的想法 description: 提出关于项目新功能的想法
labels: ["enhancement"] labels: [ "enhancement" ]
body: body:
- type: textarea - type: textarea
id: problem id: problem
@ -18,3 +18,10 @@ body:
description: 请说明需要的功能或解决方法 description: 请说明需要的功能或解决方法
validations: validations:
required: true required: true
- type: checkboxes
id: checklist
attributes:
label: 我有能力且愿意为这个功能贡献代码
options:
- label: 我有能力且愿意为这个功能贡献代码

94
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,94 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Code Security Analysis"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '45 21 * * 2'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: python
build-mode: none
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@ -58,7 +58,7 @@
“真寻是<strong>[椛椛](https://github.com/FloatTech/ZeroBot-Plugin)</strong>的好朋友!” “真寻是<strong>[椛椛](https://github.com/FloatTech/ZeroBot-Plugin)</strong>的好朋友!”
🎉喜欢真寻,于是真寻就来了!🎉 🎉 喜欢真寻,于是真寻就来了!🎉
本项目符合 [OneBot](https://github.com/howmanybots/onebot) 标准,可基于以下项目与机器人框架/平台进行交互 本项目符合 [OneBot](https://github.com/howmanybots/onebot) 标准,可基于以下项目与机器人框架/平台进行交互
@ -72,6 +72,8 @@
<div align=center> <div align=center>
<img width="100%" src="https://starify.komoridevs.icu/api/starify?owner=HibiKier&repo=zhenxun_bot" alt="starify" />
<img src="https://api.star-history.com/svg?repos=HibiKier/zhenxun_bot&type=Timeline" alt="Star Trend" width="800" /> <img src="https://api.star-history.com/svg?repos=HibiKier/zhenxun_bot&type=Timeline" alt="Star Trend" width="800" />
</div> </div>
@ -106,7 +108,7 @@ AccessToken: PUBLIC_ZHENXUN_TEST
“不要害怕,你的背后还有千千万万的 <strong>伙伴</strong> 啊!” “不要害怕,你的背后还有千千万万的 <strong>伙伴</strong> 啊!”
| 项目名称 | 主要用途 | 仓库作者 | 备注 | | 项目名称 | 主要用途 | 仓库作者 | 备注 |
| :--------------------------------------------------------------------: | :------: | :-------------------------------------------------: | :---------------------------: | | :--------------------------------------------------------------------: | :------: | :-------------------------------------------------: | :---------------------------------------------------: |
| [插件库](https://github.com/zhenxun-org/zhenxun_bot_plugins) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 原 plugins 文件夹插件 | | [插件库](https://github.com/zhenxun-org/zhenxun_bot_plugins) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 原 plugins 文件夹插件 |
| [插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 扩展插件索引库 | | [插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 扩展插件索引库 |
| [一键安装](https://github.com/soloxiaoye2022/zhenxun_bot-deploy) | 安装 | [soloxiaoye2022](https://github.com/soloxiaoye2022) | 第三方 | | [一键安装](https://github.com/soloxiaoye2022/zhenxun_bot-deploy) | 安装 | [soloxiaoye2022](https://github.com/soloxiaoye2022) | 第三方 |
@ -138,8 +140,7 @@ pip install poetry # 安装 poetry
poetry install # 安装依赖 poetry install # 安装依赖
# 开始运行 # 开始运行
poetry shell # 进入虚拟环境 poetry run python bot.py
python bot.py # 运行机器人
``` ```
## 📝 简单配置 ## 📝 简单配置
@ -156,7 +157,7 @@ python bot.py # 运行机器人
DB_URL 是基于 Tortoise ORM 的数据库连接字符串,用于指定项目所使用的数据库。以下是 DB_URL 的组成部分以及示例: DB_URL 是基于 Tortoise ORM 的数据库连接字符串,用于指定项目所使用的数据库。以下是 DB_URL 的组成部分以及示例:
格式为: ```<数据库类型>://<用户名>:<密码>@<主机>:<端口>/<数据库名>?<参数>``` 格式为: `<数据库类型>://<用户名>:<密码>@<主机>:<端口>/<数据库名>?<参数>`
- 数据库类型:表示数据库类型,例如 postgres、mysql、sqlite 等。 - 数据库类型:表示数据库类型,例如 postgres、mysql、sqlite 等。
- 用户名:数据库的用户名,例如 root。 - 用户名:数据库的用户名,例如 root。
@ -262,7 +263,7 @@ DB_URL 是基于 Tortoise ORM 的数据库连接字符串,用于指定项目
(可以告诉我你的 **github** 地址,我偷偷换掉 0v|) (可以告诉我你的 **github** 地址,我偷偷换掉 0v|)
[shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377) [A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377) [疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377) [投冥](https://afdian.net/a/144514mm) [茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377) [AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377) [爱发电用户\_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377) [qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377) [溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377) [伝木](https://afdian.net/u/246b80683f9511edba7552540025c377) [阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377) [醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377) [Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377) [本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377) [椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377) [kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377) [咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377) [Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377) [墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377) [爱发电用户\_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [noahzark](https://afdian.net/a/noahzark) [腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377) [zeroller](https://afdian.net/u/0e599e96257211ed805152540025c377) [爱发电用户\_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377) [爱发电用户\_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377) [烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377) [ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377) [爱发电用户\_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377) [爱发电用户\_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377) [爱发电用户\_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377) [MangataAkihi](https://github.com/Sakuracio) [](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377) [爱发电用户\_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377) [大魔王](https://github.com/xipesoy) [CopilotLaLaLa](https://github.com/CopilotLaLaLa) [嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377) [回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377) [十年くん](https://github.com/shinianj) [](https://afdian.net/u/9b266244f23911eca19052540025c377) [yajiwa](https://github.com/yajiwa) [爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)... [Zer](https://afdian.com/u/6bccdb2a60b411ec9ad452540025c377) [爱发电用户\_HTjk](https://afdian.com/u/6c7d0208064511ec8d7b52540025c377) [shenghuo2](https://afdian.com/u/bca13286102111eda2a052540025c377) [术樱](https://afdian.com/u/414da63a09a311ec8eb752540025c377) [飞火](https://afdian.com/u/404135f48ed711ec962152540025c377) [shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377) [A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377) [疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377) [投冥](https://afdian.net/a/144514mm) [茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377) [AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377) [爱发电用户\_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377) [qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377) [溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377) [伝木](https://afdian.net/u/246b80683f9511edba7552540025c377) [阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377) [醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377) [Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377) [本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377) [椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377) [kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377) [咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377) [Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377) [墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377) [爱发电用户\_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [noahzark](https://afdian.net/a/noahzark) [腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377) [zeroller](https://afdian.net/u/0e599e96257211ed805152540025c377) [爱发电用户\_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377) [爱发电用户\_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377) [烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377) [ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377) [爱发电用户\_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377) [爱发电用户\_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377) [爱发电用户\_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377) [MangataAkihi](https://github.com/Sakuracio) [](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377) [爱发电用户\_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377) [大魔王](https://github.com/xipesoy) [CopilotLaLaLa](https://github.com/CopilotLaLaLa) [嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377) [回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377) [十年くん](https://github.com/shinianj) [](https://afdian.net/u/9b266244f23911eca19052540025c377) [yajiwa](https://github.com/yajiwa) [爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)...
## 📜 贡献指南 ## 📜 贡献指南
@ -325,7 +326,7 @@ Project [zhenxun_bot](https://github.com/users/HibiKier/projects/2)
<img src="https://contrib.rocks/image?repo=HibiKier/zhenxun_bot&max=1000" alt="contributors"/> <img src="https://contrib.rocks/image?repo=HibiKier/zhenxun_bot&max=1000" alt="contributors"/>
</a> </a>
## 📸 WebUI界面展示 ## 📸 WebUI 界面展示
<div style="display: flex; flex-wrap: wrap; justify-content: space-between;"> <div style="display: flex; flex-wrap: wrap; justify-content: space-between;">
<div style="width: 48%; margin-bottom: 10px;"> <div style="width: 48%; margin-bottom: 10px;">

1070
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,7 @@ py-cpuinfo = "^9.0.0"
nonebot-plugin-alconna = "^0.54.0" nonebot-plugin-alconna = "^0.54.0"
tenacity = "^9.0.0" tenacity = "^9.0.0"
nonebot-plugin-uninfo = ">0.4.1" nonebot-plugin-uninfo = ">0.4.1"
nonebot-plugin-waiter = "^0.8.1"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
nonebug = "^0.4" nonebug = "^0.4"

View File

@ -9,13 +9,13 @@ arclet-alconna==1.8.35 ; python_version >= "3.10" and python_version < "4.0"
arrow==1.3.0 ; python_version >= "3.10" and python_version < "4.0" arrow==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
async-timeout==5.0.1 ; python_version >= "3.10" and python_version < "3.11.0" async-timeout==5.0.1 ; python_version >= "3.10" and python_version < "3.11.0"
asyncpg==0.30.0 ; python_version >= "3.10" and python_version < "4.0" asyncpg==0.30.0 ; python_version >= "3.10" and python_version < "4.0"
attrs==24.3.0 ; python_version >= "3.10" and python_version < "4.0" attrs==25.1.0 ; python_version >= "3.10" and python_version < "4.0"
beautifulsoup4==4.12.3 ; python_version >= "3.10" and python_version < "4.0" beautifulsoup4==4.13.3 ; python_version >= "3.10" and python_version < "4.0"
bilireq==0.2.3.post0 ; python_version >= "3.10" and python_version < "4.0" bilireq==0.2.3.post0 ; python_version >= "3.10" and python_version < "4.0"
binaryornot==0.4.4 ; python_version >= "3.10" and python_version < "4.0" binaryornot==0.4.4 ; python_version >= "3.10" and python_version < "4.0"
cashews==7.4.0 ; python_version >= "3.10" and python_version < "4.0" cashews==7.4.0 ; python_version >= "3.10" and python_version < "4.0"
cattrs==23.2.3 ; python_version >= "3.10" and python_version < "4.0" cattrs==23.2.3 ; python_version >= "3.10" and python_version < "4.0"
certifi==2024.12.14 ; python_version >= "3.10" and python_version < "4.0" certifi==2025.1.31 ; python_version >= "3.10" and python_version < "4.0"
cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy" cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
chardet==5.2.0 ; python_version >= "3.10" and python_version < "4.0" chardet==5.2.0 ; python_version >= "3.10" and python_version < "4.0"
charset-normalizer==3.4.1 ; python_version >= "3.10" and python_version < "4.0" charset-normalizer==3.4.1 ; python_version >= "3.10" and python_version < "4.0"
@ -23,27 +23,27 @@ click==8.1.8 ; python_version >= "3.10" and python_version < "4.0"
cn2an==0.5.23 ; python_version >= "3.10" and python_version < "4.0" cn2an==0.5.23 ; python_version >= "3.10" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
cookiecutter==2.6.0 ; python_version >= "3.10" and python_version < "4.0" cookiecutter==2.6.0 ; python_version >= "3.10" and python_version < "4.0"
cryptography==44.0.0 ; python_version >= "3.10" and python_version < "4.0" cryptography==44.0.1 ; python_version >= "3.10" and python_version < "4.0"
dateparser==1.2.0 ; python_version >= "3.10" and python_version < "4.0" dateparser==1.2.1 ; python_version >= "3.10" and python_version < "4.0"
distlib==0.3.9 ; python_version >= "3.10" and python_version < "4.0" distlib==0.3.9 ; python_version >= "3.10" and python_version < "4.0"
ecdsa==0.19.0 ; python_version >= "3.10" and python_version < "4.0" ecdsa==0.19.0 ; python_version >= "3.10" and python_version < "4.0"
exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "4.0" exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "4.0"
fastapi==0.115.6 ; python_version >= "3.10" and python_version < "4.0" fastapi==0.115.8 ; python_version >= "3.10" and python_version < "4.0"
feedparser==6.0.11 ; python_version >= "3.10" and python_version < "4.0" feedparser==6.0.11 ; python_version >= "3.10" and python_version < "4.0"
filelock==3.16.1 ; python_version >= "3.10" and python_version < "4.0" filelock==3.17.0 ; python_version >= "3.10" and python_version < "4.0"
greenlet==3.1.1 ; python_version >= "3.10" and python_version < "4.0" greenlet==3.1.1 ; python_version >= "3.10" and python_version < "4.0"
grpcio==1.69.0 ; python_version >= "3.10" and python_version < "4.0" grpcio==1.70.0 ; python_version >= "3.10" and python_version < "4.0"
h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0"
httpcore==0.16.3 ; python_version >= "3.10" and python_version < "4.0" httpcore==0.16.3 ; python_version >= "3.10" and python_version < "4.0"
httptools==0.6.4 ; python_version >= "3.10" and python_version < "4.0" httptools==0.6.4 ; python_version >= "3.10" and python_version < "4.0"
httpx==0.23.3 ; python_version >= "3.10" and python_version < "4.0" httpx==0.23.3 ; python_version >= "3.10" and python_version < "4.0"
idna==3.10 ; python_version >= "3.10" and python_version < "4.0" idna==3.10 ; python_version >= "3.10" and python_version < "4.0"
imagehash==4.3.1 ; python_version >= "3.10" and python_version < "4.0" imagehash==4.3.2 ; python_version >= "3.10" and python_version < "4.0"
importlib-metadata==8.5.0 ; python_version >= "3.10" and python_version < "4.0" importlib-metadata==8.6.1 ; python_version >= "3.10" and python_version < "4.0"
iso8601==1.1.0 ; python_version >= "3.10" and python_version < "4.0" iso8601==1.1.0 ; python_version >= "3.10" and python_version < "4.0"
jinja2==3.1.5 ; python_version >= "3.10" and python_version < "4.0" jinja2==3.1.5 ; python_version >= "3.10" and python_version < "4.0"
loguru==0.7.3 ; python_version >= "3.10" and python_version < "4.0" loguru==0.7.3 ; python_version >= "3.10" and python_version < "4.0"
lxml==5.3.0 ; python_version >= "3.10" and python_version < "4.0" lxml==5.3.1 ; python_version >= "3.10" and python_version < "4.0"
markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0" markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
markdown==3.7 ; python_version >= "3.10" and python_version < "4.0" markdown==3.7 ; python_version >= "3.10" and python_version < "4.0"
markupsafe==3.0.2 ; python_version >= "3.10" and python_version < "4.0" markupsafe==3.0.2 ; python_version >= "3.10" and python_version < "4.0"
@ -58,28 +58,28 @@ nonebot-plugin-apscheduler==0.5.0 ; python_version >= "3.10" and python_version
nonebot-plugin-htmlrender==0.6.0 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-htmlrender==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-session==0.2.3 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-session==0.2.3 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-uninfo==0.6.8 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-uninfo==0.6.8 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-waiter==0.8.0 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-waiter==0.8.1 ; python_version >= "3.10" and python_version < "4.0"
nonebot2==2.4.1 ; python_version >= "3.10" and python_version < "4.0" nonebot2==2.4.1 ; python_version >= "3.10" and python_version < "4.0"
noneprompt==0.1.9 ; python_version >= "3.10" and python_version < "4.0" noneprompt==0.1.9 ; python_version >= "3.10" and python_version < "4.0"
numpy==2.2.1 ; python_version >= "3.10" and python_version < "4.0" numpy==2.2.2 ; python_version >= "3.10" and python_version < "4.0"
pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0" pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0"
platformdirs==4.3.6 ; python_version >= "3.10" and python_version < "4.0" platformdirs==4.3.6 ; python_version >= "3.10" and python_version < "4.0"
playwright==1.49.1 ; python_version >= "3.10" and python_version < "4.0" playwright==1.50.0 ; python_version >= "3.10" and python_version < "4.0"
proces==0.1.7 ; python_version >= "3.10" and python_version < "4.0" proces==0.1.7 ; python_version >= "3.10" and python_version < "4.0"
prompt-toolkit==3.0.48 ; python_version >= "3.10" and python_version < "4.0" prompt-toolkit==3.0.50 ; python_version >= "3.10" and python_version < "4.0"
propcache==0.2.1 ; python_version >= "3.10" and python_version < "4.0" propcache==0.2.1 ; python_version >= "3.10" and python_version < "4.0"
protobuf==4.25.5 ; python_version >= "3.10" and python_version < "4.0" protobuf==4.25.6 ; python_version >= "3.10" and python_version < "4.0"
psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0" psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0"
py-cpuinfo==9.0.0 ; python_version >= "3.10" and python_version < "4.0" py-cpuinfo==9.0.0 ; python_version >= "3.10" and python_version < "4.0"
pyasn1==0.6.1 ; python_version >= "3.10" and python_version < "4.0" pyasn1==0.6.1 ; python_version >= "3.10" and python_version < "4.0"
pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy" pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
pydantic-core==2.27.2 ; python_version >= "3.10" and python_version < "4.0" pydantic-core==2.27.2 ; python_version >= "3.10" and python_version < "4.0"
pydantic==2.10.4 ; python_version >= "3.10" and python_version < "4.0" pydantic==2.10.6 ; python_version >= "3.10" and python_version < "4.0"
pyee==12.0.0 ; python_version >= "3.10" and python_version < "4.0" pyee==12.1.1 ; python_version >= "3.10" and python_version < "4.0"
pyfiglet==1.0.2 ; python_version >= "3.10" and python_version < "4.0" pyfiglet==1.0.2 ; python_version >= "3.10" and python_version < "4.0"
pygments==2.19.1 ; python_version >= "3.10" and python_version < "4.0" pygments==2.19.1 ; python_version >= "3.10" and python_version < "4.0"
pygtrie==2.5.0 ; python_version >= "3.10" and python_version < "4.0" pygtrie==2.5.0 ; python_version >= "3.10" and python_version < "4.0"
pymdown-extensions==10.14 ; python_version >= "3.10" and python_version < "4.0" pymdown-extensions==10.14.3 ; python_version >= "3.10" and python_version < "4.0"
pypika-tortoise==0.1.6 ; python_version >= "3.10" and python_version < "4.0" pypika-tortoise==0.1.6 ; python_version >= "3.10" and python_version < "4.0"
pypinyin==0.51.0 ; python_version >= "3.10" and python_version < "4.0" pypinyin==0.51.0 ; python_version >= "3.10" and python_version < "4.0"
python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0"
@ -88,7 +88,7 @@ python-jose==3.3.0 ; python_version >= "3.10" and python_version < "4.0"
python-markdown-math==0.8 ; python_version >= "3.10" and python_version < "4.0" python-markdown-math==0.8 ; python_version >= "3.10" and python_version < "4.0"
python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0" python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0"
python-slugify==8.0.4 ; python_version >= "3.10" and python_version < "4.0" python-slugify==8.0.4 ; python_version >= "3.10" and python_version < "4.0"
pytz==2024.2 ; python_version >= "3.10" and python_version < "4.0" pytz==2025.1 ; python_version >= "3.10" and python_version < "4.0"
pywavelets==1.8.0 ; python_version >= "3.10" and python_version < "4.0" pywavelets==1.8.0 ; python_version >= "3.10" and python_version < "4.0"
pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0" pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0"
regex==2024.11.6 ; python_version >= "3.10" and python_version < "4.0" regex==2024.11.6 ; python_version >= "3.10" and python_version < "4.0"
@ -99,12 +99,12 @@ rich==13.9.4 ; python_version >= "3.10" and python_version < "4.0"
rsa==4.9 ; python_version >= "3.10" and python_version < "4.0" rsa==4.9 ; python_version >= "3.10" and python_version < "4.0"
ruamel-yaml-clib==0.2.12 ; python_version >= "3.10" and python_version < "3.13" and platform_python_implementation == "CPython" ruamel-yaml-clib==0.2.12 ; python_version >= "3.10" and python_version < "3.13" and platform_python_implementation == "CPython"
ruamel-yaml==0.18.10 ; python_version >= "3.10" and python_version < "4.0" ruamel-yaml==0.18.10 ; python_version >= "3.10" and python_version < "4.0"
scipy==1.15.0 ; python_version >= "3.10" and python_version < "4.0" scipy==1.15.1 ; python_version >= "3.10" and python_version < "4.0"
sgmllib3k==1.0.0 ; python_version >= "3.10" and python_version < "4.0" sgmllib3k==1.0.0 ; python_version >= "3.10" and python_version < "4.0"
six==1.17.0 ; python_version >= "3.10" and python_version < "4.0" six==1.17.0 ; python_version >= "3.10" and python_version < "4.0"
sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0"
soupsieve==2.6 ; python_version >= "3.10" and python_version < "4.0" soupsieve==2.6 ; python_version >= "3.10" and python_version < "4.0"
starlette==0.41.3 ; python_version >= "3.10" and python_version < "4.0" starlette==0.45.3 ; python_version >= "3.10" and python_version < "4.0"
strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0" strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0"
tarina==0.6.8 ; python_version >= "3.10" and python_version < "4.0" tarina==0.6.8 ; python_version >= "3.10" and python_version < "4.0"
tenacity==9.0.0 ; python_version >= "3.10" and python_version < "4.0" tenacity==9.0.0 ; python_version >= "3.10" and python_version < "4.0"
@ -114,16 +114,16 @@ tomlkit==0.13.2 ; python_version >= "3.10" and python_version < "4.0"
tortoise-orm==0.20.1 ; python_version >= "3.10" and python_version < "4.0" tortoise-orm==0.20.1 ; python_version >= "3.10" and python_version < "4.0"
types-python-dateutil==2.9.0.20241206 ; python_version >= "3.10" and python_version < "4.0" types-python-dateutil==2.9.0.20241206 ; python_version >= "3.10" and python_version < "4.0"
typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0"
tzdata==2024.2 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" tzdata==2025.1 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
tzlocal==5.2 ; python_version >= "3.10" and python_version < "4.0" tzlocal==5.2 ; python_version >= "3.10" and python_version < "4.0"
ujson==5.10.0 ; python_version >= "3.10" and python_version < "4.0" ujson==5.10.0 ; python_version >= "3.10" and python_version < "4.0"
urllib3==2.3.0 ; python_version >= "3.10" and python_version < "4.0" urllib3==2.3.0 ; python_version >= "3.10" and python_version < "4.0"
uvicorn==0.34.0 ; python_version >= "3.10" and python_version < "4.0" uvicorn==0.34.0 ; python_version >= "3.10" and python_version < "4.0"
uvloop==0.21.0 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" uvloop==0.21.0 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy"
virtualenv==20.28.1 ; python_version >= "3.10" and python_version < "4.0" virtualenv==20.29.2 ; python_version >= "3.10" and python_version < "4.0"
watchfiles==0.24.0 ; python_version >= "3.10" and python_version < "4.0" watchfiles==0.24.0 ; python_version >= "3.10" and python_version < "4.0"
wcwidth==0.2.13 ; python_version >= "3.10" and python_version < "4.0" wcwidth==0.2.13 ; python_version >= "3.10" and python_version < "4.0"
websockets==14.1 ; python_version >= "3.10" and python_version < "4.0" websockets==14.2 ; python_version >= "3.10" and python_version < "4.0"
win32-setctime==1.2.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" win32-setctime==1.2.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32"
yarl==1.18.3 ; python_version >= "3.10" and python_version < "4.0" yarl==1.18.3 ; python_version >= "3.10" and python_version < "4.0"
zipp==3.21.0 ; python_version >= "3.10" and python_version < "4.0" zipp==3.21.0 ; python_version >= "3.10" and python_version < "4.0"

View File

@ -16,8 +16,10 @@ from tests.utils import _v11_group_message_event
@pytest.mark.parametrize("package_api", ["jsd", "gh"]) @pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_basic( async def test_add_plugin_basic(
package_api: str, package_api: str,
is_commit: bool,
app: App, app: App,
mocker: MockerFixture, mocker: MockerFixture,
mocked_api: MockRouter, mocked_api: MockRouter,
@ -40,6 +42,12 @@ async def test_add_plugin_basic(
if package_api != "gh": if package_api != "gh":
mocked_api["zhenxun_bot_plugins_tree"].respond(404) mocked_api["zhenxun_bot_plugins_tree"].respond(404)
if not is_commit:
mocked_api["zhenxun_bot_plugins_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_commit_proxy"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit_proxy"].respond(404)
plugin_id = 1 plugin_id = 1
async with app.test_matcher(_matcher) as ctx: async with app.test_matcher(_matcher) as ctx:
@ -67,15 +75,22 @@ async def test_add_plugin_basic(
result=None, result=None,
bot=bot, bot=bot,
) )
if is_commit:
assert mocked_api["search_image_plugin_file_init_commit"].called
assert mocked_api["basic_plugins"].called assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called assert mocked_api["extra_plugins"].called
else:
assert mocked_api["search_image_plugin_file_init"].called assert mocked_api["search_image_plugin_file_init"].called
assert mocked_api["basic_plugins_no_commit"].called
assert mocked_api["extra_plugins_no_commit"].called
assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file() assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file()
@pytest.mark.parametrize("package_api", ["jsd", "gh"]) @pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_basic_commit_version( async def test_add_plugin_basic_commit_version(
package_api: str, package_api: str,
is_commit: bool,
app: App, app: App,
mocker: MockerFixture, mocker: MockerFixture,
mocked_api: MockRouter, mocked_api: MockRouter,
@ -98,6 +113,11 @@ async def test_add_plugin_basic_commit_version(
if package_api != "gh": if package_api != "gh":
mocked_api["zhenxun_bot_plugins_tree_commit"].respond(404) mocked_api["zhenxun_bot_plugins_tree_commit"].respond(404)
if not is_commit:
mocked_api["zhenxun_bot_plugins_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_commit_proxy"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit_proxy"].respond(404)
plugin_id = 3 plugin_id = 3
async with app.test_matcher(_matcher) as ctx: async with app.test_matcher(_matcher) as ctx:
@ -125,19 +145,25 @@ async def test_add_plugin_basic_commit_version(
result=None, result=None,
bot=bot, bot=bot,
) )
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
if package_api == "jsd": if package_api == "jsd":
assert mocked_api["zhenxun_bot_plugins_metadata_commit"].called assert mocked_api["zhenxun_bot_plugins_metadata_commit"].called
if package_api == "gh": if package_api == "gh":
assert mocked_api["zhenxun_bot_plugins_tree_commit"].called assert mocked_api["zhenxun_bot_plugins_tree_commit"].called
if is_commit:
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
else:
assert mocked_api["basic_plugins_no_commit"].called
assert mocked_api["extra_plugins_no_commit"].called
assert mocked_api["bilibili_sub_plugin_file_init"].called assert mocked_api["bilibili_sub_plugin_file_init"].called
assert (mock_base_path / "plugins" / "bilibili_sub" / "__init__.py").is_file() assert (mock_base_path / "plugins" / "bilibili_sub" / "__init__.py").is_file()
@pytest.mark.parametrize("package_api", ["jsd", "gh"]) @pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_basic_is_not_dir( async def test_add_plugin_basic_is_not_dir(
package_api: str, package_api: str,
is_commit: bool,
app: App, app: App,
mocker: MockerFixture, mocker: MockerFixture,
mocked_api: MockRouter, mocked_api: MockRouter,
@ -160,6 +186,12 @@ async def test_add_plugin_basic_is_not_dir(
if package_api != "gh": if package_api != "gh":
mocked_api["zhenxun_bot_plugins_tree"].respond(404) mocked_api["zhenxun_bot_plugins_tree"].respond(404)
if not is_commit:
mocked_api["zhenxun_bot_plugins_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_commit_proxy"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit_proxy"].respond(404)
plugin_id = 0 plugin_id = 0
async with app.test_matcher(_matcher) as ctx: async with app.test_matcher(_matcher) as ctx:
@ -187,15 +219,22 @@ async def test_add_plugin_basic_is_not_dir(
result=None, result=None,
bot=bot, bot=bot,
) )
if is_commit:
assert mocked_api["jitang_plugin_file_commit"].called
assert mocked_api["basic_plugins"].called assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called assert mocked_api["extra_plugins"].called
else:
assert mocked_api["jitang_plugin_file"].called assert mocked_api["jitang_plugin_file"].called
assert mocked_api["basic_plugins_no_commit"].called
assert mocked_api["extra_plugins_no_commit"].called
assert (mock_base_path / "plugins" / "alapi" / "jitang.py").is_file() assert (mock_base_path / "plugins" / "alapi" / "jitang.py").is_file()
@pytest.mark.parametrize("package_api", ["jsd", "gh"]) @pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_extra( async def test_add_plugin_extra(
package_api: str, package_api: str,
is_commit: bool,
app: App, app: App,
mocker: MockerFixture, mocker: MockerFixture,
mocked_api: MockRouter, mocked_api: MockRouter,
@ -218,6 +257,14 @@ async def test_add_plugin_extra(
if package_api != "gh": if package_api != "gh":
mocked_api["zhenxun_github_sub_tree"].respond(404) mocked_api["zhenxun_github_sub_tree"].respond(404)
if not is_commit:
mocked_api["zhenxun_github_sub_commit"].respond(404)
mocked_api["zhenxun_github_sub_commit_proxy"].respond(404)
mocked_api["zhenxun_bot_plugins_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_commit_proxy"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit"].respond(404)
mocked_api["zhenxun_bot_plugins_index_commit_proxy"].respond(404)
plugin_id = 4 plugin_id = 4
async with app.test_matcher(_matcher) as ctx: async with app.test_matcher(_matcher) as ctx:
@ -245,9 +292,14 @@ async def test_add_plugin_extra(
result=None, result=None,
bot=bot, bot=bot,
) )
if is_commit:
assert mocked_api["github_sub_plugin_file_init_commit"].called
assert mocked_api["basic_plugins"].called assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called assert mocked_api["extra_plugins"].called
else:
assert mocked_api["github_sub_plugin_file_init"].called assert mocked_api["github_sub_plugin_file_init"].called
assert mocked_api["basic_plugins_no_commit"].called
assert mocked_api["extra_plugins_no_commit"].called
assert (mock_base_path / "plugins" / "github_sub" / "__init__.py").is_file() assert (mock_base_path / "plugins" / "github_sub" / "__init__.py").is_file()

View File

@ -112,7 +112,7 @@ async def test_plugin_store_fail(
init_mocked_api(mocked_api=mocked_api) init_mocked_api(mocked_api=mocked_api)
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins.json", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins.json",
name="basic_plugins", name="basic_plugins",
).respond(404) ).respond(404)

View File

@ -65,7 +65,7 @@ async def test_update_all_plugin_basic_need_update(
) )
assert mocked_api["basic_plugins"].called assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called assert mocked_api["extra_plugins"].called
assert mocked_api["search_image_plugin_file_init"].called assert mocked_api["search_image_plugin_file_init_commit"].called
assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file() assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file()

View File

@ -65,7 +65,7 @@ async def test_update_plugin_basic_need_update(
) )
assert mocked_api["basic_plugins"].called assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called assert mocked_api["extra_plugins"].called
assert mocked_api["search_image_plugin_file_init"].called assert mocked_api["search_image_plugin_file_init_commit"].called
assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file() assert (mock_base_path / "plugins" / "search_image" / "__init__.py").is_file()

View File

@ -30,6 +30,10 @@ def init_mocked_api(mocked_api: MockRouter) -> None:
"https://data.jsdelivr.com/v1/packages/gh/zhenxun-org/zhenxun_bot_plugins@b101fbc", "https://data.jsdelivr.com/v1/packages/gh/zhenxun-org/zhenxun_bot_plugins@b101fbc",
name="zhenxun_bot_plugins_metadata_commit", name="zhenxun_bot_plugins_metadata_commit",
).respond(json=get_response_json("zhenxun_bot_plugins_metadata.json")) ).respond(json=get_response_json("zhenxun_bot_plugins_metadata.json"))
mocked_api.get(
"https://data.jsdelivr.com/v1/packages/gh/xuanerwa/zhenxun_github_sub@f524632f78d27f9893beebdf709e0e7885cd08f1",
name="zhenxun_github_sub_metadata_commit",
).respond(json=get_response_json("zhenxun_github_sub_metadata.json"))
# tree # tree
mocked_api.get( mocked_api.get(
@ -44,6 +48,10 @@ def init_mocked_api(mocked_api: MockRouter) -> None:
"https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/git/trees/b101fbc?recursive=1", "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/git/trees/b101fbc?recursive=1",
name="zhenxun_bot_plugins_tree_commit", name="zhenxun_bot_plugins_tree_commit",
).respond(json=get_response_json("zhenxun_bot_plugins_tree.json")) ).respond(json=get_response_json("zhenxun_bot_plugins_tree.json"))
mocked_api.get(
"https://api.github.com/repos/xuanerwa/zhenxun_github_sub/git/trees/f524632f78d27f9893beebdf709e0e7885cd08f1?recursive=1",
name="zhenxun_github_sub_tree_commit",
).respond(json=get_response_json("zhenxun_github_sub_tree.json"))
mocked_api.head( mocked_api.head(
"https://raw.githubusercontent.com/", "https://raw.githubusercontent.com/",
@ -51,36 +59,89 @@ def init_mocked_api(mocked_api: MockRouter) -> None:
).respond(200, text="") ).respond(200, text="")
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins.json", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins.json",
name="basic_plugins", name="basic_plugins",
).respond(json=get_response_json("basic_plugins.json")) ).respond(json=get_response_json("basic_plugins.json"))
mocked_api.get( mocked_api.get(
"https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins@main/plugins.json", "https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins@b101fbc/plugins.json",
name="basic_plugins_jsdelivr", name="basic_plugins_jsdelivr",
).respond(200, json=get_response_json("basic_plugins.json")) ).respond(200, json=get_response_json("basic_plugins.json"))
mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins.json",
name="basic_plugins_no_commit",
).respond(json=get_response_json("basic_plugins.json"))
mocked_api.get(
"https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins@main/plugins.json",
name="basic_plugins_jsdelivr_no_commit",
).respond(200, json=get_response_json("basic_plugins.json"))
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins_index/index/plugins.json", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins_index/2ed61284873c526802752b12a3fd3b5e1a59d948/plugins.json",
name="extra_plugins", name="extra_plugins",
).respond(200, json=get_response_json("extra_plugins.json")) ).respond(200, json=get_response_json("extra_plugins.json"))
mocked_api.get( mocked_api.get(
"https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins_index@index/plugins.json", "https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins_index@2ed61284873c526802752b12a3fd3b5e1a59d948/plugins.json",
name="extra_plugins_jsdelivr", name="extra_plugins_jsdelivr",
).respond(200, json=get_response_json("extra_plugins.json")) ).respond(200, json=get_response_json("extra_plugins.json"))
mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins_index/index/plugins.json",
name="extra_plugins_no_commit",
).respond(200, json=get_response_json("extra_plugins.json"))
mocked_api.get(
"https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins_index@index/plugins.json",
name="extra_plugins_jsdelivr_no_commit",
).respond(200, json=get_response_json("extra_plugins.json"))
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/search_image/__init__.py", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/search_image/__init__.py",
name="search_image_plugin_file_init", name="search_image_plugin_file_init",
).respond(content=get_content_bytes("search_image.py")) ).respond(content=get_content_bytes("search_image.py"))
mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins/search_image/__init__.py",
name="search_image_plugin_file_init_commit",
).respond(content=get_content_bytes("search_image.py"))
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/alapi/jitang.py", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/alapi/jitang.py",
name="jitang_plugin_file", name="jitang_plugin_file",
).respond(content=get_content_bytes("jitang.py")) ).respond(content=get_content_bytes("jitang.py"))
mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins/alapi/jitang.py",
name="jitang_plugin_file_commit",
).respond(content=get_content_bytes("jitang.py"))
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/xuanerwa/zhenxun_github_sub/main/github_sub/__init__.py", "https://raw.githubusercontent.com/xuanerwa/zhenxun_github_sub/main/github_sub/__init__.py",
name="github_sub_plugin_file_init", name="github_sub_plugin_file_init",
).respond(content=get_content_bytes("github_sub.py")) ).respond(content=get_content_bytes("github_sub.py"))
mocked_api.get(
"https://raw.githubusercontent.com/xuanerwa/zhenxun_github_sub/f524632f78d27f9893beebdf709e0e7885cd08f1/github_sub/__init__.py",
name="github_sub_plugin_file_init_commit",
).respond(content=get_content_bytes("github_sub.py"))
mocked_api.get( mocked_api.get(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins/bilibili_sub/__init__.py", "https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins/bilibili_sub/__init__.py",
name="bilibili_sub_plugin_file_init", name="bilibili_sub_plugin_file_init",
).respond(content=get_content_bytes("bilibili_sub.py")) ).respond(content=get_content_bytes("bilibili_sub.py"))
mocked_api.get(
"https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/commits/main",
name="zhenxun_bot_plugins_commit",
).respond(json=get_response_json("zhenxun_bot_plugins_commit.json"))
mocked_api.get(
"https://git-api.zhenxun.org/repos/zhenxun-org/zhenxun_bot_plugins/commits/main",
name="zhenxun_bot_plugins_commit_proxy",
).respond(json=get_response_json("zhenxun_bot_plugins_commit.json"))
mocked_api.get(
"https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/commits/index",
name="zhenxun_bot_plugins_index_commit",
).respond(json=get_response_json("zhenxun_bot_plugins_index_commit.json"))
mocked_api.get(
"https://git-api.zhenxun.org/repos/zhenxun-org/zhenxun_bot_plugins_index/commits/index",
name="zhenxun_bot_plugins_index_commit_proxy",
).respond(json=get_response_json("zhenxun_bot_plugins_index_commit.json"))
mocked_api.get(
"https://api.github.com/repos/xuanerwa/zhenxun_github_sub/commits/main",
name="zhenxun_github_sub_commit",
).respond(json=get_response_json("zhenxun_github_sub_commit.json"))
mocked_api.get(
"https://git-api.zhenxun.org/repos/xuanerwa/zhenxun_github_sub/commits/main",
name="zhenxun_github_sub_commit_proxy",
).respond(json=get_response_json("zhenxun_github_sub_commit.json"))

View File

@ -0,0 +1,101 @@
{
"sha": "b101fbc",
"node_id": "C_kwDOMndPGNoAKGIxMDFmYmNlODg4NjA4ZTJiYmU1YjVmZDI3OWUxNDY1MTY4ODEyYzc",
"commit": {
"author": {
"name": "xuaner",
"email": "xuaner_wa@qq.com",
"date": "2024-09-20T12:08:27Z"
},
"committer": {
"name": "xuaner",
"email": "xuaner_wa@qq.com",
"date": "2024-09-20T12:08:27Z"
},
"message": "🐛修复B站订阅bug",
"tree": {
"sha": "0566306219a434f7122798647498faef692c1879",
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/git/trees/0566306219a434f7122798647498faef692c1879"
},
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/git/commits/b101fbce888608e2bbe5b5fd279e1465168812c7",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null,
"verified_at": null
}
},
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/commits/b101fbce888608e2bbe5b5fd279e1465168812c7",
"html_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins/commit/b101fbce888608e2bbe5b5fd279e1465168812c7",
"comments_url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/commits/b101fbce888608e2bbe5b5fd279e1465168812c7/comments",
"author": {
"login": "xuanerwa",
"id": 58063798,
"node_id": "MDQ6VXNlcjU4MDYzNzk4",
"avatar_url": "https://avatars.githubusercontent.com/u/58063798?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/xuanerwa",
"html_url": "https://github.com/xuanerwa",
"followers_url": "https://api.github.com/users/xuanerwa/followers",
"following_url": "https://api.github.com/users/xuanerwa/following{/other_user}",
"gists_url": "https://api.github.com/users/xuanerwa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/xuanerwa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/xuanerwa/subscriptions",
"organizations_url": "https://api.github.com/users/xuanerwa/orgs",
"repos_url": "https://api.github.com/users/xuanerwa/repos",
"events_url": "https://api.github.com/users/xuanerwa/events{/privacy}",
"received_events_url": "https://api.github.com/users/xuanerwa/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"committer": {
"login": "xuanerwa",
"id": 58063798,
"node_id": "MDQ6VXNlcjU4MDYzNzk4",
"avatar_url": "https://avatars.githubusercontent.com/u/58063798?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/xuanerwa",
"html_url": "https://github.com/xuanerwa",
"followers_url": "https://api.github.com/users/xuanerwa/followers",
"following_url": "https://api.github.com/users/xuanerwa/following{/other_user}",
"gists_url": "https://api.github.com/users/xuanerwa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/xuanerwa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/xuanerwa/subscriptions",
"organizations_url": "https://api.github.com/users/xuanerwa/orgs",
"repos_url": "https://api.github.com/users/xuanerwa/repos",
"events_url": "https://api.github.com/users/xuanerwa/events{/privacy}",
"received_events_url": "https://api.github.com/users/xuanerwa/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"parents": [
{
"sha": "a545dfa0c4e149595f7ddd50dc34c55513738fb9",
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/commits/a545dfa0c4e149595f7ddd50dc34c55513738fb9",
"html_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins/commit/a545dfa0c4e149595f7ddd50dc34c55513738fb9"
}
],
"stats": {
"total": 4,
"additions": 2,
"deletions": 2
},
"files": [
{
"sha": "0fbc9695db04c56174e3bff933f670d8d2df2abc",
"filename": "plugins/bilibili_sub/data_source.py",
"status": "modified",
"additions": 2,
"deletions": 2,
"changes": 4,
"blob_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins/blob/b101fbce888608e2bbe5b5fd279e1465168812c7/plugins%2Fbilibili_sub%2Fdata_source.py",
"raw_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins/raw/b101fbce888608e2bbe5b5fd279e1465168812c7/plugins%2Fbilibili_sub%2Fdata_source.py",
"contents_url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins/contents/plugins%2Fbilibili_sub%2Fdata_source.py?ref=b101fbce888608e2bbe5b5fd279e1465168812c7",
"patch": "@@ -271,14 +271,14 @@ async def _get_live_status(id_: int) -> list:\n sub = await BilibiliSub.get_or_none(sub_id=id_)\n msg_list = []\n if sub.live_status != live_status:\n+ await BilibiliSub.sub_handle(id_, live_status=live_status)\n image = None\n try:\n image_bytes = await fetch_image_bytes(cover)\n image = BuildImage(background = image_bytes)\n except Exception as e:\n logger.error(f\"图片构造失败,错误信息:{e}\")\n if sub.live_status in [0, 2] and live_status == 1 and image:\n- await BilibiliSub.sub_handle(id_, live_status=live_status)\n msg_list = [\n image,\n \"\\n\",\n@@ -322,7 +322,7 @@ async def _get_up_status(id_: int) -> list:\n video = video_info[\"list\"][\"vlist\"][0]\n latest_video_created = video[\"created\"]\n msg_list = []\n- if dynamic_img:\n+ if dynamic_img and _user.dynamic_upload_time < dynamic_upload_time:\n await BilibiliSub.sub_handle(id_, dynamic_upload_time=dynamic_upload_time)\n msg_list = [f\"{uname} 发布了动态!📢\\n\", dynamic_img, f\"\\n查看详情{link}\"]\n if ("
}
]
}

View File

@ -0,0 +1,101 @@
{
"sha": "2ed61284873c526802752b12a3fd3b5e1a59d948",
"node_id": "C_kwDOGK5Du9oAKDJlZDYxMjg0ODczYzUyNjgwMjc1MmIxMmEzZmQzYjVlMWE1OWQ5NDg",
"commit": {
"author": {
"name": "zhenxunflow[bot]",
"email": "179375394+zhenxunflow[bot]@users.noreply.github.com",
"date": "2025-01-26T09:04:55Z"
},
"committer": {
"name": "GitHub",
"email": "noreply@github.com",
"date": "2025-01-26T09:04:55Z"
},
"message": ":beers: publish plugin AI全家桶 (#235) (#236)\n\nCo-authored-by: molanp <molanp@users.noreply.github.com>",
"tree": {
"sha": "64ea463e084b6ab0def0322c6ad53799054ec9b3",
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/git/trees/64ea463e084b6ab0def0322c6ad53799054ec9b3"
},
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/git/commits/2ed61284873c526802752b12a3fd3b5e1a59d948",
"comment_count": 0,
"verification": {
"verified": true,
"reason": "valid",
"signature": "-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJnlfq3CRC1aQ7uu5UhlAAA+n0QADPVjQQIHFlNcTEgdq3LGQ1X\nm8+H5N07E5JD+83LdyU9/YOvqY/WURwFsQ0T4+23icUWEOD4LB5qZIdVJBYHseto\nbJNmYd1kZxpvsONoiK/2Uk6JoeVnEQIR+dTbB0wBlbL0lRt1WtTXHpLQbFXuXn3q\nJh4SdSj283UZ6D2sBADblPZ7DqaTmLlpgwrTPx0OH5wIhcuORkzOl6x0DabcVAYu\nu5zHSKM9c7g+jEmrqRuVy+ZlZMDPN4S3gDNzEhoTn4tn+KNzSIja4n7ZMRD+1a5X\nMIP3aXcVBqCyuYc6DU76IvjlaL/MjnlPwfOtx1zu+pNxZKNaSpojtqopp3blfk0E\n8s8lD9utDgUaUrdPWgpiMDjj+oNMye91CGomNDfv0fNGUlBGT6r48qaq1z8BwAAR\nzgDsF13kDuKTTkT/6T8CdgCpJtwvxMptUr2XFRtn4xwf/gJdqrbEc4fHTOSHqxzh\ncDfXuP+Sorla4oJ0duygTsulpr/zguX8RJWJml35VjERw54ARAVvhZn19G9qQVJo\n2QIp+xtyTjkM3yTeN4UDXFt4lDuxz3+l1MBduj+CHn+WTgxyJUpX2TA1GVfni9xT\npOMOtzuDQfDIxTNB6hFjSWATb1/E5ys1lfK09n+dRhmvC/Be+b5M4WlyX3cqy/za\ns0XxuZ+CHzLfHaPxFUem\n=VYpl\n-----END PGP SIGNATURE-----\n",
"payload": "tree 64ea463e084b6ab0def0322c6ad53799054ec9b3\nparent 5df26081d40e3000a7beedb73954d4df397c93fa\nauthor zhenxunflow[bot] <179375394+zhenxunflow[bot]@users.noreply.github.com> 1737882295 +0800\ncommitter GitHub <noreply@github.com> 1737882295 +0800\n\n:beers: publish plugin AI全家桶 (#235) (#236)\n\nCo-authored-by: molanp <molanp@users.noreply.github.com>",
"verified_at": "2025-01-26T09:04:58Z"
}
},
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/commits/2ed61284873c526802752b12a3fd3b5e1a59d948",
"html_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins_index/commit/2ed61284873c526802752b12a3fd3b5e1a59d948",
"comments_url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/commits/2ed61284873c526802752b12a3fd3b5e1a59d948/comments",
"author": {
"login": "zhenxunflow[bot]",
"id": 179375394,
"node_id": "BOT_kgDOCrENIg",
"avatar_url": "https://avatars.githubusercontent.com/in/978723?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/zhenxunflow%5Bbot%5D",
"html_url": "https://github.com/apps/zhenxunflow",
"followers_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/followers",
"following_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/following{/other_user}",
"gists_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/gists{/gist_id}",
"starred_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/subscriptions",
"organizations_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/orgs",
"repos_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/repos",
"events_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/events{/privacy}",
"received_events_url": "https://api.github.com/users/zhenxunflow%5Bbot%5D/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
},
"committer": {
"login": "web-flow",
"id": 19864447,
"node_id": "MDQ6VXNlcjE5ODY0NDQ3",
"avatar_url": "https://avatars.githubusercontent.com/u/19864447?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/web-flow",
"html_url": "https://github.com/web-flow",
"followers_url": "https://api.github.com/users/web-flow/followers",
"following_url": "https://api.github.com/users/web-flow/following{/other_user}",
"gists_url": "https://api.github.com/users/web-flow/gists{/gist_id}",
"starred_url": "https://api.github.com/users/web-flow/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/web-flow/subscriptions",
"organizations_url": "https://api.github.com/users/web-flow/orgs",
"repos_url": "https://api.github.com/users/web-flow/repos",
"events_url": "https://api.github.com/users/web-flow/events{/privacy}",
"received_events_url": "https://api.github.com/users/web-flow/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"parents": [
{
"sha": "5df26081d40e3000a7beedb73954d4df397c93fa",
"url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/commits/5df26081d40e3000a7beedb73954d4df397c93fa",
"html_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins_index/commit/5df26081d40e3000a7beedb73954d4df397c93fa"
}
],
"stats": {
"total": 11,
"additions": 11,
"deletions": 0
},
"files": [
{
"sha": "3d98392c25d38f5d375b830aed6e2298e47e5601",
"filename": "plugins.json",
"status": "modified",
"additions": 11,
"deletions": 0,
"changes": 11,
"blob_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins_index/blob/2ed61284873c526802752b12a3fd3b5e1a59d948/plugins.json",
"raw_url": "https://github.com/zhenxun-org/zhenxun_bot_plugins_index/raw/2ed61284873c526802752b12a3fd3b5e1a59d948/plugins.json",
"contents_url": "https://api.github.com/repos/zhenxun-org/zhenxun_bot_plugins_index/contents/plugins.json?ref=2ed61284873c526802752b12a3fd3b5e1a59d948",
"patch": "@@ -53,5 +53,16 @@\n \"plugin_type\": \"NORMAL\",\n \"is_dir\": true,\n \"github_url\": \"https://github.com/PackageInstaller/zhenxun_plugin_draw_painting/tree/master\"\n+ },\n+ \"AI全家桶\": {\n+ \"module\": \"zhipu_toolkit\",\n+ \"module_path\": \"zhipu_toolkit\",\n+ \"description\": \"AI全家桶一次安装到处使用省时省力省心\",\n+ \"usage\": \"AI全家桶一次安装到处使用省时省力省心\\n usage:\\n 生成图片 <prompt>\\n 生成视频 <prompt>\\n 清理我的会话: 用于清理你与AI的聊天记录\\n 或者与机器人聊天,\\n 例如;\\n @Bot抱抱\\n 小真寻老婆\",\n+ \"author\": \"molanp\",\n+ \"version\": \"0.1\",\n+ \"plugin_type\": \"NORMAL\",\n+ \"is_dir\": true,\n+ \"github_url\": \"https://github.com/molanp/zhenxun_plugin_zhipu_toolkit\"\n }\n }"
}
]
}

View File

@ -0,0 +1,101 @@
{
"sha": "f524632f78d27f9893beebdf709e0e7885cd08f1",
"node_id": "C_kwDOJAjBPdoAKGY1MjQ2MzJmNzhkMjdmOTg5M2JlZWJkZjcwOWUwZTc4ODVjZDA4ZjE",
"commit": {
"author": {
"name": "xuaner",
"email": "xuaner_wa@qq.com",
"date": "2024-11-18T18:17:15Z"
},
"committer": {
"name": "xuaner",
"email": "xuaner_wa@qq.com",
"date": "2024-11-18T18:17:15Z"
},
"message": "fix bug",
"tree": {
"sha": "b6b1b4f06cc869b9f38d7b51bdca3a2c575255e4",
"url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/git/trees/b6b1b4f06cc869b9f38d7b51bdca3a2c575255e4"
},
"url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/git/commits/f524632f78d27f9893beebdf709e0e7885cd08f1",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null,
"verified_at": null
}
},
"url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/commits/f524632f78d27f9893beebdf709e0e7885cd08f1",
"html_url": "https://github.com/xuanerwa/zhenxun_github_sub/commit/f524632f78d27f9893beebdf709e0e7885cd08f1",
"comments_url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/commits/f524632f78d27f9893beebdf709e0e7885cd08f1/comments",
"author": {
"login": "xuanerwa",
"id": 58063798,
"node_id": "MDQ6VXNlcjU4MDYzNzk4",
"avatar_url": "https://avatars.githubusercontent.com/u/58063798?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/xuanerwa",
"html_url": "https://github.com/xuanerwa",
"followers_url": "https://api.github.com/users/xuanerwa/followers",
"following_url": "https://api.github.com/users/xuanerwa/following{/other_user}",
"gists_url": "https://api.github.com/users/xuanerwa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/xuanerwa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/xuanerwa/subscriptions",
"organizations_url": "https://api.github.com/users/xuanerwa/orgs",
"repos_url": "https://api.github.com/users/xuanerwa/repos",
"events_url": "https://api.github.com/users/xuanerwa/events{/privacy}",
"received_events_url": "https://api.github.com/users/xuanerwa/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"committer": {
"login": "xuanerwa",
"id": 58063798,
"node_id": "MDQ6VXNlcjU4MDYzNzk4",
"avatar_url": "https://avatars.githubusercontent.com/u/58063798?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/xuanerwa",
"html_url": "https://github.com/xuanerwa",
"followers_url": "https://api.github.com/users/xuanerwa/followers",
"following_url": "https://api.github.com/users/xuanerwa/following{/other_user}",
"gists_url": "https://api.github.com/users/xuanerwa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/xuanerwa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/xuanerwa/subscriptions",
"organizations_url": "https://api.github.com/users/xuanerwa/orgs",
"repos_url": "https://api.github.com/users/xuanerwa/repos",
"events_url": "https://api.github.com/users/xuanerwa/events{/privacy}",
"received_events_url": "https://api.github.com/users/xuanerwa/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"parents": [
{
"sha": "91e5e2c792e79193830441d555769aa54acd2d15",
"url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/commits/91e5e2c792e79193830441d555769aa54acd2d15",
"html_url": "https://github.com/xuanerwa/zhenxun_github_sub/commit/91e5e2c792e79193830441d555769aa54acd2d15"
}
],
"stats": {
"total": 2,
"additions": 1,
"deletions": 1
},
"files": [
{
"sha": "764a5f7b81554c4c10d29486ea5d9105e505cec3",
"filename": "github_sub/__init__.py",
"status": "modified",
"additions": 1,
"deletions": 1,
"changes": 2,
"blob_url": "https://github.com/xuanerwa/zhenxun_github_sub/blob/f524632f78d27f9893beebdf709e0e7885cd08f1/github_sub%2F__init__.py",
"raw_url": "https://github.com/xuanerwa/zhenxun_github_sub/raw/f524632f78d27f9893beebdf709e0e7885cd08f1/github_sub%2F__init__.py",
"contents_url": "https://api.github.com/repos/xuanerwa/zhenxun_github_sub/contents/github_sub%2F__init__.py?ref=f524632f78d27f9893beebdf709e0e7885cd08f1",
"patch": "@@ -168,7 +168,7 @@ async def _(session: EventSession):\n # 推送\n @scheduler.scheduled_job(\n \"interval\",\n- seconds=base_config.get(\"CHECK_API_TIME\") if base_config.get(\"CHECK_TIME\") else 30,\n+ seconds=base_config.get(\"CHECK_API_TIME\") if base_config.get(\"CHECK_API_TIME\") else 30,\n )\n async def _():\n bots = nonebot.get_bots()"
}
]
}

View File

@ -125,7 +125,7 @@ async def _(session: Uninfo, arparma: Arparma, idx: Match[int]):
@_del_matcher.handle() @_del_matcher.handle()
async def _(session: Uninfo, arparma: Arparma, idx: int): async def _(session: Uninfo, arparma: Arparma, idx: int):
result = await Manager.delete_group_message(session, int(idx)) result = await Manager.delete_group_message(session, idx)
if not result: if not result:
await MessageUtils.build_message("未查找到指定id的群组欢迎消息...").finish() await MessageUtils.build_message("未查找到指定id的群组欢迎消息...").finish()
await MessageUtils.build_message(result).send() await MessageUtils.build_message(result).send()

View File

@ -22,8 +22,11 @@ BASE_PATH.mkdir(parents=True, exist_ok=True)
driver = nonebot.get_driver() driver = nonebot.get_driver()
old_file = DATA_PATH / "custom_welcome_msg" / "custom_welcome_msg.json" def __migrate():
if old_file.exists(): """首次数据迁移"""
old_file = DATA_PATH / "custom_welcome_msg" / "custom_welcome_msg.json"
if not old_file.exists():
return
try: try:
old_data: dict[str, str] = json.load(old_file.open(encoding="utf8")) old_data: dict[str, str] = json.load(old_file.open(encoding="utf8"))
for group_id, message in old_data.items(): for group_id, message in old_data.items():
@ -53,6 +56,7 @@ def migrate(path: Path):
参数: 参数:
path: 路径 path: 路径
""" """
__migrate()
text_file = path / "text.json" text_file = path / "text.json"
if not text_file.exists(): if not text_file.exists():
return return
@ -248,9 +252,11 @@ class Manager:
返回: 返回:
list: 消息内容 list: 消息内容
""" """
path = cls.get_path(session)
json_data = cls.__get_data(session) json_data = cls.__get_data(session)
if not json_data: if not json_data or not path:
return None return None
file = path / "text.json"
key_list = list(json_data.keys()) key_list = list(json_data.keys())
if idx < 0 or idx >= len(key_list): if idx < 0 or idx >= len(key_list):
return None return None

View File

@ -2,11 +2,12 @@ import os
import random import random
from nonebot import on_message from nonebot import on_message
from nonebot.adapters import Event
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import UniMsg from nonebot_plugin_alconna import UniMsg
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.path_config import IMAGE_PATH from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.configs.utils import PluginExtraData from zhenxun.configs.utils import PluginExtraData
@ -29,7 +30,22 @@ __plugin_meta__ = PluginMetadata(
).to_dict(), ).to_dict(),
) )
_matcher = on_message(rule=to_me(), priority=996, block=False)
async def rule(event: Event, message: UniMsg, session: Uninfo) -> bool:
group_id = session.group.id if session.group else None
text = message.extract_plain_text().strip()
if await BanConsole.is_ban(session.user.id, group_id):
return False
if group_id:
if await BanConsole.is_ban(None, group_id):
return False
if g := await GroupConsole.get_group(group_id):
if g.level < 0:
return False
return event.is_tome() and bool(text and len(text) < 20)
_matcher = on_message(rule=rule, priority=996, block=False)
_path = IMAGE_PATH / "_base" / "laugh" _path = IMAGE_PATH / "_base" / "laugh"
@ -37,19 +53,18 @@ _path = IMAGE_PATH / "_base" / "laugh"
@_matcher.handle() @_matcher.handle()
async def _(matcher: Matcher, message: UniMsg, session: EventSession): async def _(matcher: Matcher, message: UniMsg, session: EventSession):
gid = session.id3 or session.id2 text = message.extract_plain_text().strip()
if await BanConsole.is_ban(session.id1, gid): plugin = await PluginInfo.get_or_none(
name=text,
load_status=True,
plugin_type=PluginType.NORMAL,
block_type__isnull=True,
status=True,
)
if not plugin:
return return
if gid:
if await BanConsole.is_ban(None, gid):
return
if g := await GroupConsole.get_group(gid):
if g.level < 0:
return
if text := message.extract_plain_text().strip():
if plugin := await PluginInfo.get_or_none(
name=text, load_status=True, plugin_type=PluginType.NORMAL
):
image = None image = None
if _path.exists(): if _path.exists():
if files := os.listdir(_path): if files := os.listdir(_path):
@ -62,8 +77,6 @@ async def _(matcher: Matcher, message: UniMsg, session: EventSession):
f"但还是好心来帮帮你啦!\n请at我发送 '帮助{plugin.name}' 或者" f"但还是好心来帮帮你啦!\n请at我发送 '帮助{plugin.name}' 或者"
f" '帮助{plugin.id}' 来获取该功能帮助!" f" '帮助{plugin.id}' 来获取该功能帮助!"
) )
logger.info( logger.info("检测到功能名称当命令使用,已发送帮助信息", "功能帮助", session=session)
"检测到功能名称当命令使用,已发送帮助信息", "功能帮助", session=session
)
await MessageUtils.build_message(message_list).send(reply_to=True) await MessageUtils.build_message(message_list).send(reply_to=True)
matcher.stop_propagation() matcher.stop_propagation()

View File

@ -15,6 +15,7 @@ from zhenxun.models.group_console import GroupConsole
from zhenxun.models.level_user import LevelUser from zhenxun.models.level_user import LevelUser
from zhenxun.models.plugin_info import PluginInfo from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.plugin_limit import PluginLimit from zhenxun.models.plugin_limit import PluginLimit
from zhenxun.models.sign_user import SignUser
from zhenxun.models.user_console import UserConsole from zhenxun.models.user_console import UserConsole
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.enum import ( from zhenxun.utils.enum import (
@ -210,7 +211,9 @@ class AuthChecker:
return False return False
if plugin.plugin_type == PluginType.DEPENDANT: if plugin.plugin_type == PluginType.DEPENDANT:
return False return False
return plugin.module != "ai" if self._flmt_s.check(sid) else False if plugin.ignore_prompt:
return False
return self._flmt_s.check(sid)
async def auth( async def auth(
self, self,
@ -358,14 +361,28 @@ class AuthChecker:
group_id = channel_id group_id = channel_id
channel_id = None channel_id = None
if user_id := session.id1: if user_id := session.id1:
is_poke = isinstance(event, PokeNotifyEvent) if plugin.impression > 0:
sign_user = await SignUser.get_user(user_id)
if float(sign_user.impression) < plugin.impression:
if self.is_send_limit_message(plugin, user_id):
self._flmt_s.start_cd(user_id)
await MessageUtils.build_message(
f"好感度不足哦,当前功能需要好感度: {plugin.impression}"
"请继续签到提升好感度吧!"
).send(reply_to=True)
logger.debug(
f"{plugin.name}({plugin.module}) 用户好感度不足...",
"AuthChecker",
session=session,
)
raise IgnoredException("好感度不足...")
if group_id: if group_id:
sid = group_id or user_id sid = group_id or user_id
if await GroupConsole.is_superuser_block_plugin( if await GroupConsole.is_superuser_block_plugin(
group_id, plugin.module group_id, plugin.module
): ):
"""超级用户群组插件状态""" """超级用户群组插件状态"""
if self.is_send_limit_message(plugin, sid) and not is_poke: if self.is_send_limit_message(plugin, sid):
self._flmt_s.start_cd(group_id or user_id) self._flmt_s.start_cd(group_id or user_id)
await MessageUtils.build_message( await MessageUtils.build_message(
"超级管理员禁用了该群此功能..." "超级管理员禁用了该群此功能..."
@ -378,7 +395,7 @@ class AuthChecker:
raise IgnoredException("超级管理员禁用了该群此功能...") raise IgnoredException("超级管理员禁用了该群此功能...")
if await GroupConsole.is_normal_block_plugin(group_id, plugin.module): if await GroupConsole.is_normal_block_plugin(group_id, plugin.module):
"""群组插件状态""" """群组插件状态"""
if self.is_send_limit_message(plugin, sid) and not is_poke: if self.is_send_limit_message(plugin, sid):
self._flmt_s.start_cd(group_id or user_id) self._flmt_s.start_cd(group_id or user_id)
await MessageUtils.build_message("该群未开启此功能...").send( await MessageUtils.build_message("该群未开启此功能...").send(
reply_to=True reply_to=True
@ -392,7 +409,7 @@ class AuthChecker:
if plugin.block_type == BlockType.GROUP: if plugin.block_type == BlockType.GROUP:
"""全局群组禁用""" """全局群组禁用"""
try: try:
if self.is_send_limit_message(plugin, sid) and not is_poke: if self.is_send_limit_message(plugin, sid):
self._flmt_c.start_cd(group_id) self._flmt_c.start_cd(group_id)
await MessageUtils.build_message( await MessageUtils.build_message(
"该功能在群组中已被禁用..." "该功能在群组中已被禁用..."
@ -415,7 +432,7 @@ class AuthChecker:
if plugin.block_type == BlockType.PRIVATE: if plugin.block_type == BlockType.PRIVATE:
"""全局私聊禁用""" """全局私聊禁用"""
try: try:
if self.is_send_limit_message(plugin, sid) and not is_poke: if self.is_send_limit_message(plugin, sid):
self._flmt_c.start_cd(user_id) self._flmt_c.start_cd(user_id)
await MessageUtils.build_message( await MessageUtils.build_message(
"该功能在私聊中已被禁用..." "该功能在私聊中已被禁用..."
@ -442,7 +459,7 @@ class AuthChecker:
"AuthChecker", "AuthChecker",
session=session, session=session,
) )
if self.is_send_limit_message(plugin, sid) and not is_poke: if self.is_send_limit_message(plugin, sid):
self._flmt_s.start_cd(group_id or user_id) self._flmt_s.start_cd(group_id or user_id)
await MessageUtils.build_message("全局未开启此功能...").send() await MessageUtils.build_message("全局未开启此功能...").send()
raise IgnoredException("全局未开启此功能...") raise IgnoredException("全局未开启此功能...")

View File

@ -29,6 +29,7 @@ _flmt = FreqLimiter(300)
async def _( async def _(
matcher: Matcher, bot: Bot, event: Event, state: T_State, session: EventSession matcher: Matcher, bot: Bot, event: Event, state: T_State, session: EventSession
): ):
extra = {}
if plugin := matcher.plugin: if plugin := matcher.plugin:
if metadata := plugin.metadata: if metadata := plugin.metadata:
extra = metadata.extra extra = metadata.extra
@ -66,7 +67,12 @@ async def _(
time_str = f"{hours} 小时 {minute}分钟" time_str = f"{hours} 小时 {minute}分钟"
else: else:
time_str = f"{minute} 分钟" time_str = f"{minute} 分钟"
if time != -1 and ban_result and _flmt.check(user_id): if (
not extra.get("ignore_prompt")
and time != -1
and ban_result
and _flmt.check(user_id)
):
_flmt.start_cd(user_id) _flmt.start_cd(user_id)
await MessageUtils.build_message( await MessageUtils.build_message(
[ [

View File

@ -75,6 +75,7 @@ async def _handle_setting(
is_show=extra_data.is_show, is_show=extra_data.is_show,
ignore_prompt=extra_data.ignore_prompt, ignore_prompt=extra_data.ignore_prompt,
parent=(plugin.parent_plugin.module_name if plugin.parent_plugin else None), parent=(plugin.parent_plugin.module_name if plugin.parent_plugin else None),
impression=setting.impression,
) )
) )
if extra_data.limits: if extra_data.limits:
@ -123,7 +124,6 @@ async def _():
"admin_level", "admin_level",
"plugin_type", "plugin_type",
"is_show", "is_show",
"ignore_prompt",
] ]
) )
update_list.append(plugin) update_list.append(plugin)

View File

@ -80,12 +80,17 @@ class ShopManage:
返回: 返回:
dict: 插件信息数据 dict: 插件信息数据
""" """
default_github_url = await GithubUtils.parse_github_url( default_github_repo = GithubUtils.parse_github_url(DEFAULT_GITHUB_URL)
DEFAULT_GITHUB_URL extra_github_repo = GithubUtils.parse_github_url(EXTRA_GITHUB_URL)
).get_raw_download_urls("plugins.json") for repo_info in [default_github_repo, extra_github_repo]:
extra_github_url = await GithubUtils.parse_github_url( if await repo_info.update_repo_commit():
EXTRA_GITHUB_URL logger.info(f"获取最新提交: {repo_info.branch}", "插件管理")
).get_raw_download_urls("plugins.json") else:
logger.warning(f"获取最新提交失败: {repo_info}", "插件管理")
default_github_url = await default_github_repo.get_raw_download_urls(
"plugins.json"
)
extra_github_url = await extra_github_repo.get_raw_download_urls("plugins.json")
res = await AsyncHttpx.get(default_github_url) res = await AsyncHttpx.get(default_github_url)
res2 = await AsyncHttpx.get(extra_github_url) res2 = await AsyncHttpx.get(extra_github_url)
@ -218,6 +223,10 @@ class ShopManage:
files: list[str] files: list[str]
repo_api: RepoAPI repo_api: RepoAPI
repo_info = GithubUtils.parse_github_url(github_url) repo_info = GithubUtils.parse_github_url(github_url)
if await repo_info.update_repo_commit():
logger.info(f"获取最新提交: {repo_info.branch}", "插件管理")
else:
logger.warning(f"获取最新提交失败: {repo_info}", "插件管理")
logger.debug(f"成功获取仓库信息: {repo_info}", "插件管理") logger.debug(f"成功获取仓库信息: {repo_info}", "插件管理")
for repo_api in GithubUtils.iter_api_strategies(): for repo_api in GithubUtils.iter_api_strategies():
try: try:

View File

@ -1,4 +1,6 @@
import asyncio
from datetime import datetime from datetime import datetime
import random
import time import time
from nonebot import on_message, on_request from nonebot import on_message, on_request
@ -40,7 +42,15 @@ __plugin_meta__ = PluginMetadata(
help="是否自动同意好友添加", help="是否自动同意好友添加",
type=bool, type=bool,
default_value=False, default_value=False,
) ),
RegisterConfig(
module="invite_manager",
key="AUTO_ADD_GROUP",
value=False,
help="是否自动同意邀请入群",
type=bool,
default_value=False,
),
], ],
).to_dict(), ).to_dict(),
) )
@ -81,6 +91,7 @@ async def _(bot: v12Bot | v11Bot, event: FriendRequestEvent, session: EventSessi
"好友请求", "好友请求",
target=event.user_id, target=event.user_id,
) )
await asyncio.sleep(random.randint(1, 10))
await bot.set_friend_add_request(flag=event.flag, approve=True) await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.create( await FriendUser.create(
user_id=str(user["user_id"]), user_name=user["nickname"] user_id=str(user["user_id"]), user_name=user["nickname"]
@ -104,7 +115,7 @@ async def _(bot: v12Bot | v11Bot, event: FriendRequestEvent, session: EventSessi
await PlatformUtils.send_superuser( await PlatformUtils.send_superuser(
bot, bot,
f"*****一份好友申请*****\n" f"*****一份好友申请*****\n"
f"ID: {f.id}" f"ID: {f.id}\n"
f"昵称:{nickname}({event.user_id})\n" f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'' if base_config.get('AUTO_ADD_FRIEND') else '×'}\n" f"自动同意:{'' if base_config.get('AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n" f"日期:{str(datetime.now()).split('.')[0]}\n"
@ -118,10 +129,10 @@ async def _(bot: v12Bot | v11Bot, event: FriendRequestEvent, session: EventSessi
async def _(bot: v12Bot | v11Bot, event: GroupRequestEvent, session: EventSession): async def _(bot: v12Bot | v11Bot, event: GroupRequestEvent, session: EventSession):
if event.sub_type != "invite": if event.sub_type != "invite":
return return
if str(event.user_id) in bot.config.superusers: if str(event.user_id) in bot.config.superusers or base_config.get("AUTO_ADD_GROUP"):
try: try:
logger.debug( logger.debug(
"超级用户自动同意加入群聊", "超级用户自动同意加入群聊或开启自动同意入群",
"群聊请求", "群聊请求",
session=event.user_id, session=event.user_id,
target=event.group_id, target=event.group_id,
@ -154,12 +165,42 @@ async def _(bot: v12Bot | v11Bot, event: GroupRequestEvent, session: EventSessio
) )
except ActionFailed as e: except ActionFailed as e:
logger.error( logger.error(
"级用户自动同意加入群聊发生错误", "级用户自动同意加入群聊或开启自动同意入群,加入群组发生错误",
"群聊请求", "群聊请求",
session=event.user_id, session=event.user_id,
target=event.group_id, target=event.group_id,
e=e, e=e,
) )
if str(event.user_id) not in bot.config.superusers and base_config.get(
"AUTO_ADD_GROUP"
):
# 非超级用户邀请自动加入群组
nickname = await FriendUser.get_user_name(str(event.user_id))
f = await FgRequest.create(
request_type=RequestType.GROUP,
platform=session.platform,
bot_id=bot.self_id,
flag=event.flag,
user_id=str(event.user_id),
nickname=nickname,
group_id=str(event.group_id),
handle_type=RequestHandleType.APPROVE,
)
await PlatformUtils.send_superuser(
bot,
f"*****一份入群申请*****\n"
f"ID{f.id}\n"
f"申请人:{nickname}({event.user_id})\n群聊:"
f"{event.group_id}\n邀请日期:{datetime.now().replace(microsecond=0)}\n"
"注: 该请求已自动同意",
)
await asyncio.sleep(random.randint(1, 5))
await bot.send_private_msg(
user_id=event.user_id,
message=f"管理员已开启自动同意群组邀请,请不要让{BotConfig.self_nickname}受委屈哦(狠狠监控)"
"\n在群组中 群组管理员与群主 允许使用管理员帮助"
"包括ban与功能开关等\n请在群组中发送 '管理员帮助'",
)
elif Timer.check(f"{event.user_id}:{event.group_id}"): elif Timer.check(f"{event.user_id}:{event.group_id}"):
logger.debug( logger.debug(
f"收录 用户[{event.user_id}] 群聊[{event.group_id}] 群聊请求", f"收录 用户[{event.user_id}] 群聊[{event.group_id}] 群聊请求",

View File

@ -18,6 +18,7 @@ from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.utils import BaseBlock, Command, PluginExtraData, RegisterConfig from zhenxun.configs.utils import BaseBlock, Command, PluginExtraData, RegisterConfig
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.decorator.shop import NotMeetUseConditionsException
from zhenxun.utils.depends import UserName from zhenxun.utils.depends import UserName
from zhenxun.utils.enum import BlockType, PluginType from zhenxun.utils.enum import BlockType, PluginType
from zhenxun.utils.exception import GoodsNotFound from zhenxun.utils.exception import GoodsNotFound
@ -202,6 +203,12 @@ async def _(
await MessageUtils.build_message( await MessageUtils.build_message(
f"没有找到道具 {name.result} 或道具数量不足..." f"没有找到道具 {name.result} 或道具数量不足..."
).send(reply_to=True) ).send(reply_to=True)
except NotMeetUseConditionsException as e:
if info := e.get_info():
await MessageUtils.build_message(info).finish() # type: ignore
await MessageUtils.build_message(
f"使用道具 {name.result} 的条件不满足..."
).send(reply_to=True)
@_matcher.assign("gold-list") @_matcher.assign("gold-list")

View File

@ -194,7 +194,6 @@ class ShopManage:
"num": num, "num": num,
"text": text, "text": text,
"goods_name": goods.name, "goods_name": goods.name,
"message": message,
} }
@classmethod @classmethod
@ -203,8 +202,9 @@ class ShopManage:
args: MappingProxyType, args: MappingProxyType,
param: ShopParam, param: ShopParam,
session: Uninfo, session: Uninfo,
message: UniMsg,
**kwargs, **kwargs,
) -> list[Any]: ) -> dict:
"""解析参数 """解析参数
参数: 参数:
@ -212,31 +212,30 @@ class ShopManage:
param: ShopParam param: ShopParam
返回: 返回:
list[Any]: 参数 dict: 参数
""" """
param_list = []
_bot = param.bot _bot = param.bot
param.bot = None param.bot = None
param_json = {**param.to_dict(), **param.extra_data} param_json = {
param_json["bot"] = _bot "bot": _bot,
for par in args.keys(): "kwargs": kwargs,
if par in ["shop_param"]: **param.to_dict(),
param_list.append(param) **param.extra_data,
elif par in ["session"]: "session": session,
param_list.append(session) "message": message,
elif par in ["message"]: }
param_list.append(kwargs.get("message")) for key in list(param_json.keys()):
elif par not in ["args", "kwargs"]: if key not in args:
param_list.append(param_json.get(par)) del param_json[key]
if kwargs.get(par) is not None: return param_json
del kwargs[par]
return param_list
@classmethod @classmethod
async def run_before_after( async def run_before_after(
cls, cls,
goods: Goods, goods: Goods,
param: ShopParam, param: ShopParam,
session: Uninfo,
message: UniMsg,
run_type: Literal["after", "before"], run_type: Literal["after", "before"],
**kwargs, **kwargs,
): ):
@ -250,16 +249,19 @@ class ShopManage:
fun_list = goods.before_handle if run_type == "before" else goods.after_handle fun_list = goods.before_handle if run_type == "before" else goods.after_handle
if fun_list: if fun_list:
for func in fun_list: for func in fun_list:
args = inspect.signature(func).parameters if args := inspect.signature(func).parameters:
if args and next(iter(args.keys())) != "kwargs":
if asyncio.iscoroutinefunction(func): if asyncio.iscoroutinefunction(func):
await func(*cls.__parse_args(args, param, **kwargs)) await func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
else: else:
func(*cls.__parse_args(args, param, **kwargs)) func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
elif asyncio.iscoroutinefunction(func): elif asyncio.iscoroutinefunction(func):
await func(**kwargs) await func()
else: else:
func(**kwargs) func()
@classmethod @classmethod
async def __run( async def __run(
@ -267,6 +269,7 @@ class ShopManage:
goods: Goods, goods: Goods,
param: ShopParam, param: ShopParam,
session: Uninfo, session: Uninfo,
message: UniMsg,
**kwargs, **kwargs,
) -> str | UniMessage | None: ) -> str | UniMessage | None:
"""运行道具函数 """运行道具函数
@ -280,18 +283,20 @@ class ShopManage:
""" """
args = inspect.signature(goods.func).parameters # type: ignore args = inspect.signature(goods.func).parameters # type: ignore
if goods.func: if goods.func:
if args and next(iter(args.keys())) != "kwargs": if args:
return ( return (
await goods.func(*cls.__parse_args(args, param, session, **kwargs)) await goods.func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
if asyncio.iscoroutinefunction(goods.func) if asyncio.iscoroutinefunction(goods.func)
else goods.func(*cls.__parse_args(args, param, session, **kwargs)) else goods.func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
) )
if asyncio.iscoroutinefunction(goods.func): if asyncio.iscoroutinefunction(goods.func):
return await goods.func( return await goods.func()
**kwargs,
)
else: else:
return goods.func(**kwargs) return goods.func()
@classmethod @classmethod
async def use( async def use(
@ -339,12 +344,12 @@ class ShopManage:
) )
if num > param.max_num_limit: if num > param.max_num_limit:
return f"{goods_info.goods_name} 单次使用最大数量为{param.max_num_limit}..." return f"{goods_info.goods_name} 单次使用最大数量为{param.max_num_limit}..."
await cls.run_before_after(goods, param, "before", **kwargs) await cls.run_before_after(goods, param, session, message, "before", **kwargs)
result = await cls.__run(goods, param, session, **kwargs) result = await cls.__run(goods, param, session, message, **kwargs)
await UserConsole.use_props( await UserConsole.use_props(
session.user.id, goods_info.uuid, num, PlatformUtils.get_platform(session) session.user.id, goods_info.uuid, num, PlatformUtils.get_platform(session)
) )
await cls.run_before_after(goods, param, "after", **kwargs) await cls.run_before_after(goods, param, session, message, "after", **kwargs)
if not result and param.send_success_msg: if not result and param.send_success_msg:
result = f"使用道具 {goods.name} {num} 次成功!" result = f"使用道具 {goods.name} {num} 次成功!"
return result return result
@ -473,35 +478,42 @@ class ShopManage:
user = await UserConsole.get_user(user_id, platform) user = await UserConsole.get_user(user_id, platform)
if not user.props: if not user.props:
return None return None
is_change = False
for uuid in list(user.props.keys()): user.props = {uuid: count for uuid, count in user.props.items() if count > 0}
if user.props[uuid] <= 0:
is_change = True goods_list = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
del user.props[uuid] goods_by_uuid = {item.uuid: item for item in goods_list}
if is_change:
await user.save(update_fields=["props"]) table_rows = []
result = await GoodsInfo.filter(uuid__in=user.props.keys()).all() for i, prop_uuid in enumerate(user.props):
data_list = [] prop = goods_by_uuid.get(prop_uuid)
uuid2goods = {item.uuid: item for item in result} if not prop:
column_name = ["-", "使用ID", "名称", "数量", "简介"] continue
for i, p in enumerate(user.props):
if prop := uuid2goods.get(p):
icon = "" icon = ""
if prop.icon:
icon_path = ICON_PATH / prop.icon icon_path = ICON_PATH / prop.icon
if icon_path.exists(): icon = (icon_path, 33, 33) if icon_path.exists() else ""
icon = (icon_path, 33, 33)
data_list.append( table_rows.append(
[ [
icon, icon,
i, i,
prop.goods_name, prop.goods_name,
user.props[p], user.props[prop_uuid],
prop.goods_description, prop.goods_description,
] ]
) )
if not table_rows:
return None
column_name = ["-", "使用ID", "名称", "数量", "简介"]
return await ImageTemplate.table_page( return await ImageTemplate.table_page(
f"{name}的道具仓库", "", column_name, data_list f"{name}的道具仓库",
"通过 使用道具[ID/名称] 令道具生效",
column_name,
table_rows,
) )
@classmethod @classmethod

View File

@ -83,7 +83,7 @@ class SignManage:
) )
data_list.append( data_list.append(
[ [
f"{i+1}", f"{i + 1}",
(bytes, 30, 30) if user[3] == "qq" else "", (bytes, 30, 30) if user[3] == "qq" else "",
uid2name.get(user[0]), uid2name.get(user[0]),
user[1], user[1],

View File

@ -5,6 +5,7 @@ from nonebot.adapters import Bot
from nonebot.params import Command from nonebot.params import Command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import Text as alcText from nonebot_plugin_alconna import Text as alcText
from nonebot_plugin_alconna import UniMsg from nonebot_plugin_alconna import UniMsg
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
@ -41,7 +42,9 @@ __plugin_meta__ = PluginMetadata(
).to_dict(), ).to_dict(),
) )
_matcher = on_command("广播", priority=1, permission=SUPERUSER, block=True) _matcher = on_command(
"广播", priority=1, permission=SUPERUSER, block=True, rule=to_me()
)
@_matcher.handle() @_matcher.handle()

View File

@ -1,11 +1,8 @@
import asyncio
import random
from nonebot.adapters import Bot from nonebot.adapters import Bot
import nonebot_plugin_alconna as alc import nonebot_plugin_alconna as alc
# from nonebot.adapters.discord import Bot as DiscordBot
# from nonebot.adapters.dodo import Bot as DodoBot
# from nonebot.adapters.kaiheila import Bot as KaiheilaBot
# from nonebot.adapters.onebot.v11 import Bot as v11Bot
# from nonebot.adapters.onebot.v12 import Bot as v12Bot
from nonebot_plugin_alconna import Image, UniMsg from nonebot_plugin_alconna import Image, UniMsg
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
@ -59,6 +56,7 @@ class BroadcastManage:
session=session, session=session,
target=f"{group.group_id}:{group.channel_id}", target=f"{group.group_id}:{group.channel_id}",
) )
await asyncio.sleep(random.randint(1, 3))
else: else:
logger.warning("target为空", "广播", session=session) logger.warning("target为空", "广播", session=session)
except Exception as e: except Exception as e:

View File

@ -16,6 +16,7 @@ from nonebot_plugin_alconna import (
) )
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
from zhenxun.configs.config import BotConfig
from zhenxun.configs.path_config import IMAGE_PATH from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.configs.utils import PluginExtraData from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.fg_request import FgRequest from zhenxun.models.fg_request import FgRequest
@ -134,14 +135,15 @@ async def _(
"r": RequestHandleType.REFUSED, "r": RequestHandleType.REFUSED,
"i": RequestHandleType.IGNORE, "i": RequestHandleType.IGNORE,
} }
req = None
handle_type = type_dict[handle[-1]] handle_type = type_dict[handle[-1]]
try: try:
if handle_type == RequestHandleType.APPROVE: if handle_type == RequestHandleType.APPROVE:
await FgRequest.approve(bot, id) req = await FgRequest.approve(bot, id)
if handle_type == RequestHandleType.REFUSED: if handle_type == RequestHandleType.REFUSED:
await FgRequest.refused(bot, id) req = await FgRequest.refused(bot, id)
if handle_type == RequestHandleType.IGNORE: if handle_type == RequestHandleType.IGNORE:
await FgRequest.ignore(id) req = await FgRequest.ignore(id)
except NotFoundError: except NotFoundError:
await MessageUtils.build_message("未发现此id的请求...").finish(reply_to=True) await MessageUtils.build_message("未发现此id的请求...").finish(reply_to=True)
except Exception: except Exception:
@ -149,7 +151,14 @@ async def _(
reply_to=True reply_to=True
) )
logger.info("处理请求", arparma.header_result, session=session) logger.info("处理请求", arparma.header_result, session=session)
await MessageUtils.build_message("成功处理请求!").finish(reply_to=True) await MessageUtils.build_message("成功处理请求!").send(reply_to=True)
if req and handle_type == RequestHandleType.APPROVE:
await bot.send_private_msg(
user_id=req.user_id,
message=f"管理员已同意此次群组邀请,请不要让{BotConfig.self_nickname}受委屈哦(狠狠监控)"
"\n在群组中 群组管理员与群主 允许使用管理员帮助"
"包括ban与功能开关等\n请在群组中发送 '管理员帮助'",
)
@_read_matcher.handle() @_read_matcher.handle()

View File

@ -1,3 +1,4 @@
import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
import time import time
@ -11,6 +12,7 @@ from zhenxun.configs.config import BotConfig
from zhenxun.models.bot_connect_log import BotConnectLog from zhenxun.models.bot_connect_log import BotConnectLog
from zhenxun.models.chat_history import ChatHistory from zhenxun.models.chat_history import ChatHistory
from zhenxun.models.statistics import Statistics from zhenxun.models.statistics import Statistics
from zhenxun.services.log import logger
from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.platform import PlatformUtils
from ....base_model import BaseResultModel, QueryModel from ....base_model import BaseResultModel, QueryModel
@ -63,10 +65,17 @@ class ApiDataSource:
bot_info = BotInfo( bot_info = BotInfo(
self_id=bot.self_id, nickname=nickname, ava_url=ava_url, platform=platform self_id=bot.self_id, nickname=nickname, ava_url=ava_url, platform=platform
) )
group_list, _ = await PlatformUtils.get_group_list(bot, True) try:
friend_list, _ = await PlatformUtils.get_friend_list(bot) group, friend = await asyncio.gather(
bot_info.group_count = len(group_list) PlatformUtils.get_group_list(bot, True),
bot_info.friend_count = len(friend_list) PlatformUtils.get_friend_list(bot),
)
bot_info.group_count = len(group[0])
bot_info.friend_count = len(friend[0])
except Exception as e:
logger.warning("获取bot好友/群组信息失败...", "WebUi", e=e)
bot_info.group_count = 0
bot_info.friend_count = 0
bot_info.day_call = await Statistics.filter( bot_info.day_call = await Statistics.filter(
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute), create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute),
bot_id=bot.self_id, bot_id=bot.self_id,

View File

@ -110,11 +110,18 @@ class ApiDataSource:
create_time__gte=now - timedelta(hours=now.hour), create_time__gte=now - timedelta(hours=now.hour),
).count() ).count()
# 群聊数量 # 群聊数量
select_bot.group_count = len(await PlatformUtils.get_group_list(select_bot.bot)) try:
select_bot.group_count = len(
(await PlatformUtils.get_group_list(select_bot.bot, True))[0]
)
# 好友数量 # 好友数量
select_bot.friend_count = len( select_bot.friend_count = len(
await PlatformUtils.get_friend_list(select_bot.bot) (await PlatformUtils.get_friend_list(select_bot.bot))[0]
) )
except Exception as e:
logger.warning("获取bot好友/群组信息失败...", "WebUi", e=e)
select_bot.group_count = 0
select_bot.friend_count = 0
select_bot.status = await BotConsole.get_bot_status(select_bot.self_id) select_bot.status = await BotConsole.get_bot_status(select_bot.self_id)
# 连接时间 # 连接时间
select_bot.connect_time = bot_live.get(select_bot.self_id) or 0 select_bot.connect_time = bot_live.get(select_bot.self_id) or 0

View File

@ -166,6 +166,42 @@ class PluginSetting(BaseModel):
"""是否限制超级用户""" """是否限制超级用户"""
cost_gold: int = 0 cost_gold: int = 0
"""调用插件花费金币""" """调用插件花费金币"""
impression: float = 0.0
"""调用插件好感度限制"""
class AICallableProperties(BaseModel):
type: str
"""参数类型"""
description: str
"""参数描述"""
enums: list[str] | None = None
"""参数枚举"""
class AICallableParam(BaseModel):
type: str
"""类型"""
properties: dict[str, AICallableProperties]
"""参数列表"""
required: list[str]
"""必要参数"""
class AICallableTag(BaseModel):
name: str
"""工具名称"""
parameters: AICallableParam | None = None
"""工具参数"""
description: str
"""工具描述"""
func: Callable | None = None
"""工具函数"""
def to_dict(self):
result = model_dump(self)
del result["func"]
return result
class SchedulerModel(BaseModel): class SchedulerModel(BaseModel):
@ -247,6 +283,8 @@ class PluginExtraData(BaseModel):
"""常用sql""" """常用sql"""
is_show: bool = True is_show: bool = True
"""是否显示在菜单中""" """是否显示在菜单中"""
smart_tools: list[AICallableTag] | None = None
"""智能模式函数工具集"""
def to_dict(self, **kwargs): def to_dict(self, **kwargs):
return model_dump(self, **kwargs) return model_dump(self, **kwargs)

View File

@ -1,3 +1,5 @@
from typing_extensions import Self
from nonebot.adapters import Bot from nonebot.adapters import Bot
from tortoise import fields from tortoise import fields
@ -38,7 +40,7 @@ class FgRequest(Model):
table_description = "好友群组请求" table_description = "好友群组请求"
@classmethod @classmethod
async def approve(cls, bot: Bot, id: int): async def approve(cls, bot: Bot, id: int) -> Self:
"""同意请求 """同意请求
参数: 参数:
@ -48,10 +50,10 @@ class FgRequest(Model):
异常: 异常:
NotFoundError: 未发现请求 NotFoundError: 未发现请求
""" """
await cls._handle_request(bot, id, RequestHandleType.APPROVE) return await cls._handle_request(bot, id, RequestHandleType.APPROVE)
@classmethod @classmethod
async def refused(cls, bot: Bot, id: int): async def refused(cls, bot: Bot, id: int) -> Self:
"""拒绝请求 """拒绝请求
参数: 参数:
@ -61,10 +63,10 @@ class FgRequest(Model):
异常: 异常:
NotFoundError: 未发现请求 NotFoundError: 未发现请求
""" """
await cls._handle_request(bot, id, RequestHandleType.REFUSED) return await cls._handle_request(bot, id, RequestHandleType.REFUSED)
@classmethod @classmethod
async def ignore(cls, id: int): async def ignore(cls, id: int) -> Self:
"""忽略请求 """忽略请求
参数: 参数:
@ -73,7 +75,7 @@ class FgRequest(Model):
异常: 异常:
NotFoundError: 未发现请求 NotFoundError: 未发现请求
""" """
await cls._handle_request(None, id, RequestHandleType.IGNORE) return await cls._handle_request(None, id, RequestHandleType.IGNORE)
@classmethod @classmethod
async def expire(cls, id: int): async def expire(cls, id: int):
@ -93,7 +95,7 @@ class FgRequest(Model):
bot: Bot | None, bot: Bot | None,
id: int, id: int,
handle_type: RequestHandleType, handle_type: RequestHandleType,
): ) -> Self:
"""处理请求 """处理请求
参数: 参数:
@ -126,3 +128,4 @@ class FgRequest(Model):
sub_type="invite", sub_type="invite",
approve=handle_type == RequestHandleType.APPROVE, approve=handle_type == RequestHandleType.APPROVE,
) )
return req

View File

@ -52,6 +52,8 @@ class PluginInfo(Model):
"""父插件""" """父插件"""
is_show = fields.BooleanField(default=True, description="是否显示在帮助中") is_show = fields.BooleanField(default=True, description="是否显示在帮助中")
"""是否显示在帮助中""" """是否显示在帮助中"""
impression = fields.FloatField(default=0, description="插件好感度限制")
"""插件好感度限制"""
class Meta: # pyright: ignore [reportIncompatibleVariableOverride] class Meta: # pyright: ignore [reportIncompatibleVariableOverride]
table = "plugin_info" table = "plugin_info"
@ -87,4 +89,5 @@ class PluginInfo(Model):
"ALTER TABLE plugin_info ADD COLUMN parent character varying(255);", "ALTER TABLE plugin_info ADD COLUMN parent character varying(255);",
"ALTER TABLE plugin_info ADD COLUMN is_show boolean DEFAULT true;", "ALTER TABLE plugin_info ADD COLUMN is_show boolean DEFAULT true;",
"ALTER TABLE plugin_info ADD COLUMN ignore_prompt boolean DEFAULT false;", "ALTER TABLE plugin_info ADD COLUMN ignore_prompt boolean DEFAULT false;",
"ALTER TABLE plugin_info ADD COLUMN impression float DEFAULT 0;",
] ]

View File

@ -36,6 +36,24 @@ class SignUser(Model):
table = "sign_users" table = "sign_users"
table_description = "用户签到数据表" table_description = "用户签到数据表"
@classmethod
async def get_user(cls, user_id: str, platform: str | None = None) -> "SignUser":
"""获取签到用户
参数:
user_id: 用户id
platform: 平台.
返回:
Self: SignUser
"""
user_console = await UserConsole.get_user(user_id, platform)
user, _ = await SignUser.get_or_create(
user_id=user_id,
defaults={"user_console": user_console, "platform": platform},
)
return user
@classmethod @classmethod
async def sign( async def sign(
cls, cls,

View File

@ -5,3 +5,4 @@ require("nonebot_plugin_alconna")
require("nonebot_plugin_session") require("nonebot_plugin_session")
require("nonebot_plugin_htmlrender") require("nonebot_plugin_htmlrender")
require("nonebot_plugin_uninfo") require("nonebot_plugin_uninfo")
require("nonebot_plugin_waiter")

View File

@ -106,3 +106,19 @@ class SqlUtils:
f"Unsupported database type: {db_class_name}", query.__module__ f"Unsupported database type: {db_class_name}", query.__module__
) )
return query return query
@classmethod
def add_column(
cls,
table_name: str,
column_name: str,
column_type: str,
default: str | None = None,
not_null: bool = False,
) -> str:
sql = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}"
if default:
sql += f" DEFAULT {default}"
if not_null:
sql += " NOT NULL"
return sql

View File

@ -1,16 +1,24 @@
from anyio import EndOfStream
from httpx import ConnectError, HTTPStatusError, TimeoutException from httpx import ConnectError, HTTPStatusError, TimeoutException
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
class Retry: class Retry:
@staticmethod @staticmethod
def api(): def api(
retry_count: int = 3, wait: int = 1, exception: tuple[type[Exception], ...] = ()
):
"""接口调用重试""" """接口调用重试"""
base_exceptions = (
TimeoutException,
ConnectError,
HTTPStatusError,
EndOfStream,
*exception,
)
return retry( return retry(
reraise=True, reraise=True,
stop=stop_after_attempt(3), stop=stop_after_attempt(retry_count),
wait=wait_fixed(1), wait=wait_fixed(wait),
retry=retry_if_exception_type( retry=retry_if_exception_type(base_exceptions),
(TimeoutException, ConnectError, HTTPStatusError)
),
) )

View File

@ -33,3 +33,11 @@ RELEASE_SOURCE_FORMAT = (
"https://codeload.github.com/{owner}/{repo}/legacy.{compress}/refs/tags/{version}" "https://codeload.github.com/{owner}/{repo}/legacy.{compress}/refs/tags/{version}"
) )
"""release 源码格式""" """release 源码格式"""
GIT_API_COMMIT_FORMAT = "https://api.github.com/repos/{owner}/{repo}/commits/{branch}"
"""git api commit地址格式"""
GIT_API_PROXY_COMMIT_FORMAT = (
"https://git-api.zhenxun.org/repos/{owner}/{repo}/commits/{branch}"
)
"""git api commit地址格式 (代理)"""

View File

@ -1,3 +1,4 @@
import contextlib
from typing import Protocol from typing import Protocol
from aiocache import cached from aiocache import cached
@ -7,7 +8,13 @@ from strenum import StrEnum
from zhenxun.utils.http_utils import AsyncHttpx from zhenxun.utils.http_utils import AsyncHttpx
from .const import CACHED_API_TTL, GIT_API_TREES_FORMAT, JSD_PACKAGE_API_FORMAT from .const import (
CACHED_API_TTL,
GIT_API_COMMIT_FORMAT,
GIT_API_PROXY_COMMIT_FORMAT,
GIT_API_TREES_FORMAT,
JSD_PACKAGE_API_FORMAT,
)
from .func import ( from .func import (
get_fastest_archive_formats, get_fastest_archive_formats,
get_fastest_raw_formats, get_fastest_raw_formats,
@ -58,9 +65,29 @@ class RepoInfo(BaseModel):
for url_format in url_formats for url_format in url_formats
] ]
async def update_repo_commit(self):
with contextlib.suppress(Exception):
newest_commit = await self.get_newest_commit(
self.owner, self.repo, self.branch
)
if newest_commit:
self.branch = newest_commit
return True
return False
def to_dict(self, **kwargs): def to_dict(self, **kwargs):
return model_dump(self, **kwargs) return model_dump(self, **kwargs)
@classmethod
@cached(ttl=CACHED_API_TTL)
async def get_newest_commit(cls, owner: str, repo: str, branch: str) -> str:
commit_url = GIT_API_COMMIT_FORMAT.format(owner=owner, repo=repo, branch=branch)
commit_url_proxy = GIT_API_PROXY_COMMIT_FORMAT.format(
owner=owner, repo=repo, branch=branch
)
resp = await AsyncHttpx().get([commit_url, commit_url_proxy])
return "" if resp.status_code != 200 else resp.json()["sha"]
class APIStrategy(Protocol): class APIStrategy(Protocol):
"""API策略""" """API策略"""

View File

@ -204,9 +204,9 @@ class AsyncHttpx:
) )
@classmethod @classmethod
async def get_content(cls, url: str, **kwargs) -> bytes | None: async def get_content(cls, url: str, **kwargs) -> bytes:
res = await cls.get(url, **kwargs) res = await cls.get(url, **kwargs)
return res.content if res and res.status_code == 200 else None return res.content
@classmethod @classmethod
async def download_file( async def download_file(

View File

@ -1,3 +1,4 @@
import asyncio
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
import random import random
from typing import Literal from typing import Literal
@ -156,7 +157,8 @@ class PlatformUtils:
返回: 返回:
UserData | None: 用户数据 UserData | None: 用户数据
""" """
if interface := get_interface(bot): if not (interface := get_interface(bot)):
return None
member = None member = None
user = None user = None
if channel_id: if channel_id:
@ -173,26 +175,26 @@ class PlatformUtils:
user = await interface.get_user(user_id) user = await interface.get_user(user_id)
if not user: if not user:
return None return None
if member: return (
return UserData( UserData(
name=user.name or "", name=user.name or "",
card=member.nick, card=member.nick,
user_id=user.id, user_id=user.id,
group_id=group_id, group_id=group_id,
channel_id=channel_id, channel_id=channel_id,
role=member.role.id if member.role else None, role=member.role.id if member.role else None,
join_time=int(member.joined_at.timestamp()) join_time=(
if member.joined_at int(member.joined_at.timestamp()) if member.joined_at else None
else None, ),
) )
else: if member
return UserData( else UserData(
name=user.name or "", name=user.name or "",
user_id=user.id, user_id=user.id,
group_id=group_id, group_id=group_id,
channel_id=channel_id, channel_id=channel_id,
) )
return None )
@classmethod @classmethod
async def get_user_avatar( async def get_user_avatar(
@ -343,6 +345,23 @@ class PlatformUtils:
return "qq" if platform.startswith("qq") else platform return "qq" if platform.startswith("qq") else platform
return "unknown" return "unknown"
@classmethod
def is_forward_merge_supported(cls, t: Bot | Uninfo) -> bool:
"""是否支持转发消息
参数:
t: bot | Uninfo
返回:
bool: 是否支持转发消息
"""
if not isinstance(t, Bot):
return t.basic["scope"] == SupportScope.qq_client
if interface := get_interface(t):
info = interface.basic_info()
return info["scope"] == SupportScope.qq_client
return False
@classmethod @classmethod
async def get_group_list( async def get_group_list(
cls, bot: Bot, only_group: bool = False cls, bot: Bot, only_group: bool = False
@ -539,6 +558,7 @@ async def broadcast_group(
target, _bot target, _bot
) )
logger.debug("发送成功", log_cmd, target=key) logger.debug("发送成功", log_cmd, target=key)
await asyncio.sleep(random.randint(1, 3))
else: else:
logger.warning("target为空", log_cmd, target=key) logger.warning("target为空", log_cmd, target=key)
except Exception as e: except Exception as e:

View File

@ -5,6 +5,8 @@ from nonebot_plugin_session import EventSession
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.config import Config from zhenxun.configs.config import Config
from zhenxun.models.ban_console import BanConsole
from zhenxun.models.group_console import GroupConsole
from zhenxun.models.level_user import LevelUser from zhenxun.models.level_user import LevelUser
from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.platform import PlatformUtils
@ -89,3 +91,21 @@ def notice_rule(event_type: type | list[type]) -> Rule:
return False return False
return Rule(_rule) return Rule(_rule)
def is_allowed_call() -> Rule:
"""是否允许调用插件"""
async def _rule(session: Uninfo) -> bool:
group_id = session.group.id if session.group else None
if await BanConsole.is_ban(session.user.id, group_id):
return False
if group_id:
if await BanConsole.is_ban(None, group_id):
return False
if g := await GroupConsole.get_group(group_id):
if g.level < 0:
return False
return True
return Rule(_rule)