更改冲突

This commit is contained in:
HibiKier 2025-04-12 15:18:06 +08:00
commit d811eaa3bc
161 changed files with 13649 additions and 1975 deletions

View File

@ -6,7 +6,7 @@ SESSION_RUNNING_EXPRESSION="别急呀,小真寻要宕机了!QAQ"
NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"] NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
SESSION_EXPIRE_TIMEOUT=30 SESSION_EXPIRE_TIMEOUT=00:00:30
ALCONNA_USE_COMMAND_START=True ALCONNA_USE_COMMAND_START=True

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

@ -18,3 +18,10 @@ body:
description: 请说明需要的功能或解决方法 description: 请说明需要的功能或解决方法
validations: validations:
required: true required: true
- type: checkboxes
id: checklist
attributes:
label: 我有能力且愿意为这个功能贡献代码
options:
- label: 我有能力且愿意为这个功能贡献代码

40
.github/actions/setup-python/action.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Setup Python
description: Setup Python
inputs:
python-version:
description: Python version
required: false
default: "3.10"
env-dir:
description: Environment directory
required: false
default: "."
no-root:
description: Do not install package in the environment
required: false
default: "false"
runs:
using: "composite"
steps:
- name: Install poetry
run: pipx install poetry
shell: bash
- uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
cache: "poetry"
cache-dependency-path: |
./poetry.lock
${{ inputs.env-dir }}/poetry.lock
- run: |
cd ${{ inputs.env-dir }}
if [ "${{ inputs.no-root }}" = "true" ]; then
poetry install --all-extras --no-root
else
poetry install --all-extras
fi
shell: bash

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}}"

11
.github/workflows/linting.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: Sequential Lint and Type Check
on: [push, pull_request]
jobs:
ruff-call:
uses: ./.github/workflows/ruff.yml
pyright-call:
needs: ruff-call
uses: ./.github/workflows/pyright.yml

55
.github/workflows/pyright.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Pyright Lint
on:
workflow_call:
workflow_dispatch:
inputs:
python-version:
description: "Python version"
required: false
type: choice
options:
- "all"
- "3.10"
- "3.11"
- "3.12"
default: "all"
debug-mode:
description: "enable debug mode"
required: false
type: boolean
default: false
jobs:
pyright:
name: Pyright Lint
runs-on: ubuntu-latest
concurrency:
group: pyright-${{ github.ref }}-${{ matrix.env }}
cancel-in-progress: true
strategy:
matrix:
env: [pydantic-v1, pydantic-v2]
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Setup Python environment
uses: ./.github/actions/setup-python
with:
env-dir: ./envs/${{ matrix.env }}
no-root: true
- run: |
(cd ./envs/${{ matrix.env }} && echo "$(poetry env info --path)/bin" >> $GITHUB_PATH)
if [ "${{ matrix.env }}" = "pydantic-v1" ]; then
sed -i 's/PYDANTIC_V2 = true/PYDANTIC_V2 = false/g' ./pyproject.toml
fi
shell: bash
- name: Run Pyright Check
uses: jakebailey/pyright-action@v2
with:
pylance-version: latest-release

20
.github/workflows/ruff.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Ruff Lint
on:
workflow_call:
jobs:
ruff:
name: Ruff Lint
runs-on: ubuntu-latest
concurrency:
group: ruff-${{ github.ref }}
cancel-in-progress: true
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Ruff
uses: astral-sh/ruff-action@v3
- name: Run Ruff Check
run: ruff check

View File

@ -2,8 +2,6 @@
"recommendations": [ "recommendations": [
"charliermarsh.ruff", "charliermarsh.ruff",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"ms-python.black-formatter",
"ms-python.isort",
"ms-python.python", "ms-python.python",
"ms-python.vscode-pylance" "ms-python.vscode-pylance"
] ]

View File

@ -16,6 +16,7 @@
"jsdelivr", "jsdelivr",
"kaiheila", "kaiheila",
"lolicon", "lolicon",
"Mahiro",
"nonebot", "nonebot",
"onebot", "onebot",
"pixiv", "pixiv",
@ -24,19 +25,19 @@
"tobytes", "tobytes",
"ujson", "ujson",
"unban", "unban",
"Uninfo",
"userinfo", "userinfo",
"zhenxun", "zhenxun"
"jsdelivr"
], ],
"python.analysis.autoImportCompletions": true, "python.analysis.autoImportCompletions": true,
"python.testing.pytestArgs": ["tests"], "python.testing.pytestArgs": ["tests"],
"python.testing.unittestEnabled": false, "python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true, "python.testing.pytestEnabled": true,
"[python]": { "[python]": {
"editor.defaultFormatter": "charliermarsh.ruff", // 使 Ruff "editor.defaultFormatter": "charliermarsh.ruff",
"editor.wordBasedSuggestions": "allDocuments", "editor.wordBasedSuggestions": "allDocuments",
"editor.formatOnType": true, "editor.formatOnType": true,
"editor.formatOnSave": true, // "editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit", "source.fixAll.ruff": "explicit",
"source.organizeImports": "explicit" "source.organizeImports": "explicit"

View File

@ -44,7 +44,7 @@
<div align=center> <div align=center>
[文档](https://hibikier.github.io/zhenxun_bot/) [文档](https://zhenxun-org.github.io/zhenxun_bot/)
</div> </div>
@ -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) | 第三方 |
@ -122,7 +124,7 @@ AccessToken: PUBLIC_ZHENXUN_TEST
- 通过 Config 配置项将所有插件配置统计保存至 config.yaml利于统一用户修改 - 通过 Config 配置项将所有插件配置统计保存至 config.yaml利于统一用户修改
- 方便增删插件,原生 nonebot2 matcher不需要额外修改仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息` - 方便增删插件,原生 nonebot2 matcher不需要额外修改仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
- 提供了 cd阻塞每日次数等限制仅仅通过简单的属性就可以生成一个限制例如`PluginCdBlock` 等 - 提供了 cd阻塞每日次数等限制仅仅通过简单的属性就可以生成一个限制例如`PluginCdBlock` 等
- **更多详细请通过 [传送门](https://hibikier.github.io/zhenxun_bot/) 查看文档!** - **更多详细请通过 [传送门](https://zhenxun-org.github.io/zhenxun_bot/) 查看文档!**
## 🛠️ 简单部署 ## 🛠️ 简单部署
@ -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)...
## 📜 贡献指南 ## 📜 贡献指南

8
bot.py
View File

@ -1,8 +1,8 @@
import nonebot import nonebot
# from nonebot.adapters.discord import Adapter as DiscordAdapter # from nonebot.adapters.discord import Adapter as DiscordAdapter
from nonebot.adapters.dodo import Adapter as DoDoAdapter # from nonebot.adapters.dodo import Adapter as DoDoAdapter
from nonebot.adapters.kaiheila import Adapter as KaiheilaAdapter # from nonebot.adapters.kaiheila import Adapter as KaiheilaAdapter
from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter
nonebot.init() nonebot.init()
@ -10,8 +10,8 @@ nonebot.init()
driver = nonebot.get_driver() driver = nonebot.get_driver()
driver.register_adapter(OneBotV11Adapter) driver.register_adapter(OneBotV11Adapter)
driver.register_adapter(KaiheilaAdapter) # driver.register_adapter(KaiheilaAdapter)
driver.register_adapter(DoDoAdapter) # driver.register_adapter(DoDoAdapter)
# driver.register_adapter(DiscordAdapter) # driver.register_adapter(DiscordAdapter)
from zhenxun.services.db_context import disconnect, init from zhenxun.services.db_context import disconnect, init

67
docker-compose-dev.yml Normal file
View File

@ -0,0 +1,67 @@
services:
db:
image: postgres:15
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: zhenxun
volumes:
- pgdata:/var/lib/postgresql/data
labels:
- "prometheus.io/scrape=true"
- "prometheus.io/port=9187"
postgres-exporter:
image: prometheuscommunity/postgres-exporter
environment:
DATA_SOURCE_NAME: "postgresql://postgres:password@db:5432/zhenxun?sslmode=disable"
ports:
- "9187:9187"
depends_on:
- db
redis:
image: redis:7
ports:
- "6379:6379"
labels:
- "prometheus.io/scrape=true"
- "prometheus.io/port=9121"
redis-exporter:
image: oliver006/redis_exporter
environment:
REDIS_ADDR: redis://redis:6379
ports:
- "9121:9121"
depends_on:
- redis
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
grafana:
image: grafana/grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
volumes:
pgdata:
prometheus_data:
grafana_data:

4811
envs/pydantic-v1/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
[tool.poetry]
name = "zhenxun_bot"
version = "0.2.4"
description = "基于 Nonebot2 和 go-cqhttp 开发,以 postgresql 作为数据库非常可爱的绪山真寻bot"
authors = ["HibiKier <775757368@qq.com>"]
license = "AGPL"
package-mode = false
[[tool.poetry.source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple/"
priority = "primary"
[tool.poetry.dependencies]
python = "^3.10"
playwright = "^1.41.1"
nonebot-adapter-onebot = "^2.3.1"
nonebot-plugin-apscheduler = "^0.5"
tortoise-orm = { extras = ["asyncpg"], version = "^0.20.0" }
cattrs = "^23.2.3"
ruamel-yaml = "^0.18.5"
strenum = "^0.4.15"
nonebot-plugin-session = "^0.2.3"
ujson = "^5.9.0"
nb-cli = "^1.3.0"
nonebot2 = { extras = ["fastapi"], version = "^2.3.3" }
pillow = "^10.0.0"
retrying = "^1.3.4"
aiofiles = "^23.2.1"
nonebot-plugin-htmlrender = ">=0.6.0,<1.0.0"
pypinyin = "^0.51.0"
beautifulsoup4 = "^4.12.3"
lxml = "^5.1.0"
psutil = "^5.9.8"
feedparser = "^6.0.11"
imagehash = "^4.3.1"
cn2an = "^0.5.22"
dateparser = "^1.2.0"
bilireq = "0.2.3post0"
python-jose = { extras = ["cryptography"], version = "^3.3.0" }
python-multipart = "^0.0.9"
aiocache = "^0.12.2"
py-cpuinfo = "^9.0.0"
nonebot-plugin-alconna = "^0.54.0"
tenacity = "^9.0.0"
nonebot-plugin-uninfo = ">0.4.1"
pydantic = "1.10.18"
[tool.poetry.group.dev.dependencies]
nonebug = "^0.4"
pytest-cov = "^5.0.0"
pytest-mock = "^3.6.1"
pytest-asyncio = "^0.25"
pytest-xdist = "^3.3.1"
respx = "^0.21.1"
ruff = "^0.8.0"
pre-commit = "^4.0.0"
[tool.nonebot]
plugins = [
"nonebot_plugin_apscheduler",
"nonebot_plugin_session",
"nonebot_plugin_htmlrender",
"nonebot_plugin_alconna",
]
plugin_dirs = ["zhenxun/services", "zhenxun/builtin_plugins", "zhenxun/plugins"]
adapters = [
{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
# { name = "DoDo", module_name = "nonebot.adapters.dodo" },
# { name = "开黑啦", module_name = "nonebot.adapters.kaiheila" },
]
[tool.ruff]
line-length = 88
target-version = "py310"
[tool.ruff.format]
line-ending = "lf"
[tool.ruff.lint]
select = [
"F", # Pyflakes
"W", # pycodestyle warnings
"E", # pycodestyle errors
"I", # isort
"UP", # pyupgrade
"ASYNC", # flake8-async
"C4", # flake8-comprehensions
"T10", # flake8-debugger
"T20", # flake8-print
"PYI", # flake8-pyi
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"TID", # flake8-tidy-imports
"RUF", # Ruff-specific rules
]
ignore = [
"E402", # module-import-not-at-top-of-file
"UP037", # quoted-annotation
"RUF001", # ambiguous-unicode-character-string
"RUF002", # ambiguous-unicode-character-docstring
"RUF003", # ambiguous-unicode-character-comment
"TID252", # relative-imports
]
[tool.ruff.lint.isort]
force-sort-within-sections = true
known-first-party = ["zhenxun", "tests/*"]
extra-standard-library = ["typing_extensions"]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true
[tool.pyright]
pythonVersion = "3.10"
pythonPlatform = "All"
defineConstant = { PYDANTIC_V2 = true }
executionEnvironments = [
{ root = "./tests", extraPaths = [
"./",
] },
{ root = "./" },
]
typeCheckingMode = "standard"
reportShadowedImports = false
disableBytesTypePromotions = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

4905
envs/pydantic-v2/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
[tool.poetry]
name = "zhenxun_bot"
version = "0.2.4"
description = "基于 Nonebot2 和 go-cqhttp 开发,以 postgresql 作为数据库非常可爱的绪山真寻bot"
authors = ["HibiKier <775757368@qq.com>"]
license = "AGPL"
package-mode = false
[[tool.poetry.source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple/"
priority = "primary"
[tool.poetry.dependencies]
python = "^3.10"
playwright = "^1.41.1"
nonebot-adapter-onebot = "^2.3.1"
nonebot-plugin-apscheduler = "^0.5"
tortoise-orm = { extras = ["asyncpg"], version = "^0.20.0" }
cattrs = "^23.2.3"
ruamel-yaml = "^0.18.5"
strenum = "^0.4.15"
nonebot-plugin-session = "^0.2.3"
ujson = "^5.9.0"
nb-cli = "^1.3.0"
nonebot2 = { extras = ["fastapi"], version = "^2.3.3" }
pillow = "^10.0.0"
retrying = "^1.3.4"
aiofiles = "^23.2.1"
nonebot-plugin-htmlrender = ">=0.6.0,<1.0.0"
pypinyin = "^0.51.0"
beautifulsoup4 = "^4.12.3"
lxml = "^5.1.0"
psutil = "^5.9.8"
feedparser = "^6.0.11"
imagehash = "^4.3.1"
cn2an = "^0.5.22"
dateparser = "^1.2.0"
bilireq = "0.2.3post0"
python-jose = { extras = ["cryptography"], version = "^3.3.0" }
python-multipart = "^0.0.9"
aiocache = "^0.12.2"
py-cpuinfo = "^9.0.0"
nonebot-plugin-alconna = "^0.54.0"
tenacity = "^9.0.0"
nonebot-plugin-uninfo = ">0.4.1"
pydantic = "2.10.6"
[tool.poetry.group.dev.dependencies]
nonebug = "^0.4"
pytest-cov = "^5.0.0"
pytest-mock = "^3.6.1"
pytest-asyncio = "^0.25"
pytest-xdist = "^3.3.1"
respx = "^0.21.1"
ruff = "^0.8.0"
pre-commit = "^4.0.0"
[tool.nonebot]
plugins = [
"nonebot_plugin_apscheduler",
"nonebot_plugin_session",
"nonebot_plugin_htmlrender",
"nonebot_plugin_alconna",
]
plugin_dirs = ["zhenxun/services", "zhenxun/builtin_plugins", "zhenxun/plugins"]
adapters = [
{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
# { name = "DoDo", module_name = "nonebot.adapters.dodo" },
# { name = "开黑啦", module_name = "nonebot.adapters.kaiheila" },
]
[tool.ruff]
line-length = 88
target-version = "py310"
[tool.ruff.format]
line-ending = "lf"
[tool.ruff.lint]
select = [
"F", # Pyflakes
"W", # pycodestyle warnings
"E", # pycodestyle errors
"I", # isort
"UP", # pyupgrade
"ASYNC", # flake8-async
"C4", # flake8-comprehensions
"T10", # flake8-debugger
"T20", # flake8-print
"PYI", # flake8-pyi
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"TID", # flake8-tidy-imports
"RUF", # Ruff-specific rules
]
ignore = [
"E402", # module-import-not-at-top-of-file
"UP037", # quoted-annotation
"RUF001", # ambiguous-unicode-character-string
"RUF002", # ambiguous-unicode-character-docstring
"RUF003", # ambiguous-unicode-character-comment
"TID252", # relative-imports
]
[tool.ruff.lint.isort]
force-sort-within-sections = true
known-first-party = ["zhenxun", "tests/*"]
extra-standard-library = ["typing_extensions"]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true
[tool.pyright]
pythonVersion = "3.10"
pythonPlatform = "All"
defineConstant = { PYDANTIC_V2 = true }
executionEnvironments = [
{ root = "./tests", extraPaths = [
"./",
] },
{ root = "./" },
]
typeCheckingMode = "standard"
reportShadowedImports = false
disableBytesTypePromotions = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

2554
poetry.lock generated

File diff suppressed because it is too large Load Diff

12
prometheus.yml Normal file
View File

@ -0,0 +1,12 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'postgresql'
static_configs:
- targets: [ 'postgres-exporter:9187' ]
- job_name: 'redis'
static_configs:
- targets: [ 'redis-exporter:9121' ]

View File

@ -15,24 +15,19 @@ priority = "primary"
python = "^3.10" python = "^3.10"
playwright = "^1.41.1" playwright = "^1.41.1"
nonebot-adapter-onebot = "^2.3.1" nonebot-adapter-onebot = "^2.3.1"
nonebot-plugin-apscheduler = "^0.3.0" nonebot-plugin-apscheduler = "^0.5"
tortoise-orm = { extras = ["asyncpg"], version = "^0.20.0" } tortoise-orm = { extras = ["asyncpg"], version = "^0.20.0" }
cattrs = "^23.2.3" cattrs = "^23.2.3"
ruamel-yaml = "^0.18.5" ruamel-yaml = "^0.18.5"
strenum = "^0.4.15" strenum = "^0.4.15"
nonebot-plugin-session = "^0.2.3" nonebot-plugin-session = "^0.2.3"
ujson = "^5.9.0" ujson = "^5.9.0"
nonebot-adapter-kaiheila = "^0.3.0"
nb-cli = "^1.3.0" nb-cli = "^1.3.0"
nonebot2 = "^2.1.3" nonebot2 = { extras = ["fastapi"], version = "^2.3.3" }
pydantic = "1.10.18"
nonebot-adapter-discord = "^0.1.3"
nonebot-adapter-dodo = "^0.1.4"
pillow = "^10.0.0" pillow = "^10.0.0"
retrying = "^1.3.4" retrying = "^1.3.4"
aiofiles = "^23.2.1" aiofiles = "^23.2.1"
nonebot-plugin-htmlrender = "^0.3.0" nonebot-plugin-htmlrender = ">=0.6.0,<1.0.0"
nonebot-plugin-userinfo = "^0.1.3"
pypinyin = "^0.51.0" pypinyin = "^0.51.0"
beautifulsoup4 = "^4.12.3" beautifulsoup4 = "^4.12.3"
lxml = "^5.1.0" lxml = "^5.1.0"
@ -46,14 +41,17 @@ python-jose = { extras = ["cryptography"], version = "^3.3.0" }
python-multipart = "^0.0.9" python-multipart = "^0.0.9"
aiocache = "^0.12.2" aiocache = "^0.12.2"
py-cpuinfo = "^9.0.0" py-cpuinfo = "^9.0.0"
nonebot-plugin-uninfo = "^0.4.1"
nonebot-plugin-alconna = "^0.54.0" nonebot-plugin-alconna = "^0.54.0"
tenacity = "^9.0.0"
nonebot-plugin-uninfo = ">0.4.1"
nonebot-plugin-waiter = "^0.8.1"
multidict = ">=6.0.0,!=6.3.2"
[tool.poetry.dev-dependencies] [tool.poetry.group.dev.dependencies]
nonebug = "^0.4" nonebug = "^0.4"
pytest-cov = "^5.0.0" pytest-cov = "^5.0.0"
pytest-mock = "^3.6.1" pytest-mock = "^3.6.1"
pytest-asyncio = "^0.23.5" pytest-asyncio = "^0.25"
pytest-xdist = "^3.3.1" pytest-xdist = "^3.3.1"
respx = "^0.21.1" respx = "^0.21.1"
ruff = "^0.8.0" ruff = "^0.8.0"
@ -65,14 +63,13 @@ plugins = [
"nonebot_plugin_apscheduler", "nonebot_plugin_apscheduler",
"nonebot_plugin_session", "nonebot_plugin_session",
"nonebot_plugin_htmlrender", "nonebot_plugin_htmlrender",
"nonebot_plugin_userinfo",
"nonebot_plugin_alconna", "nonebot_plugin_alconna",
] ]
plugin_dirs = ["zhenxun/services", "zhenxun/builtin_plugins", "zhenxun/plugins"] plugin_dirs = ["zhenxun/services", "zhenxun/builtin_plugins", "zhenxun/plugins"]
adapters = [ adapters = [
{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }, { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
{ name = "DoDo", module_name = "nonebot.adapters.dodo" }, # { name = "DoDo", module_name = "nonebot.adapters.dodo" },
{ name = "开黑啦", module_name = "nonebot.adapters.kaiheila" }, # { name = "开黑啦", module_name = "nonebot.adapters.kaiheila" },
] ]
[tool.ruff] [tool.ruff]

View File

@ -1,50 +1,49 @@
aiocache==0.12.3 ; python_version >= "3.10" and python_version < "4.0" aiocache==0.12.3 ; python_version >= "3.10" and python_version < "4.0"
aiofiles==23.2.1 ; python_version >= "3.10" and python_version < "4.0" aiofiles==23.2.1 ; python_version >= "3.10" and python_version < "4.0"
aiosqlite==0.17.0 ; python_version >= "3.10" and python_version < "4.0" aiosqlite==0.17.0 ; python_version >= "3.10" and python_version < "4.0"
anyio==4.7.0 ; python_version >= "3.10" and python_version < "4.0" annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
anyio==4.8.0 ; python_version >= "3.10" and python_version < "4.0"
apscheduler==3.11.0 ; python_version >= "3.10" and python_version < "4.0" apscheduler==3.11.0 ; python_version >= "3.10" and python_version < "4.0"
arclet-alconna-tools==0.7.10 ; python_version >= "3.10" and python_version < "4.0" arclet-alconna-tools==0.7.10 ; python_version >= "3.10" and python_version < "4.0"
arclet-alconna==1.8.35 ; python_version >= "3.10" and python_version < "4.0" 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"
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.2.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"
cachetools==5.5.0 ; 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.8.30 ; 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.0 ; python_version >= "3.10" and python_version < "4.0" charset-normalizer==3.4.1 ; python_version >= "3.10" and python_version < "4.0"
click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" click==8.1.8 ; python_version >= "3.10" and python_version < "4.0"
cn2an==0.5.22 ; 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 (platform_system == "Windows" or sys_platform == "win32") colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (platform_system == "Windows" or sys_platform == "win32")
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"
emoji==2.14.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.68.1 ; 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.4 ; 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"
@ -53,38 +52,35 @@ msgpack==1.1.0 ; python_version >= "3.10" and python_version < "4.0"
multidict==6.1.0 ; python_version >= "3.10" and python_version < "4.0" multidict==6.1.0 ; python_version >= "3.10" and python_version < "4.0"
nb-cli==1.4.2 ; python_version >= "3.10" and python_version < "4.0" nb-cli==1.4.2 ; python_version >= "3.10" and python_version < "4.0"
nepattern==0.7.7 ; python_version >= "3.10" and python_version < "4.0" nepattern==0.7.7 ; python_version >= "3.10" and python_version < "4.0"
nonebot-adapter-discord==0.1.8 ; python_version >= "3.10" and python_version < "4.0"
nonebot-adapter-dodo==0.1.4 ; python_version >= "3.10" and python_version < "4.0"
nonebot-adapter-kaiheila==0.3.4 ; python_version >= "3.10" and python_version < "4.0"
nonebot-adapter-onebot==2.4.6 ; python_version >= "3.10" and python_version < "4.0" nonebot-adapter-onebot==2.4.6 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-alconna==0.54.1 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-alconna==0.54.2 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-apscheduler==0.3.0 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-apscheduler==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-htmlrender==0.3.5 ; 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.4.1 ; 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-userinfo==0.1.3 ; python_version >= "3.10" and python_version < "4.0" nonebot-plugin-waiter==0.8.1 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-waiter==0.8.0 ; 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.0 ; python_version >= "3.10" and python_version < "4.0" nonebot2[fastapi]==2.4.1 ; python_version >= "3.10" and python_version < "4.0"
nonebot2[fastapi]==2.4.0 ; 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.0 ; 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==1.10.18 ; python_version >= "3.10" and python_version < "4.0" pydantic-core==2.27.2 ; python_version >= "3.10" and python_version < "4.0"
pyee==12.0.0 ; python_version >= "3.10" and python_version < "4.0" pydantic==2.10.6 ; 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.18.0 ; 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.12 ; 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" pypinyin==0.51.0 ; python_version >= "3.10" and python_version < "4"
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"
@ -93,7 +89,7 @@ python-jose[cryptography]==3.3.0 ; python_version >= "3.10" and python_version <
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"
@ -103,32 +99,32 @@ rfc3986[idna2008]==1.5.0 ; python_version >= "3.10" and python_version < "4.0"
rich==13.9.4 ; python_version >= "3.10" and python_version < "4.0" rich==13.9.4 ; python_version >= "3.10" and python_version < "4.0"
rsa==4.9 ; python_version >= "3.10" and python_version < "4" rsa==4.9 ; python_version >= "3.10" and python_version < "4"
ruamel-yaml-clib==0.2.12 ; platform_python_implementation == "CPython" and python_version < "3.13" and python_version >= "3.10" ruamel-yaml-clib==0.2.12 ; platform_python_implementation == "CPython" and python_version < "3.13" and python_version >= "3.10"
ruamel-yaml==0.18.6 ; 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.14.1 ; python_version >= "3.10" and python_version < "4.0" scipy==1.15.1 ; python_version >= "3.10" and python_version < "4.0"
setuptools==75.6.0 ; 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"
text-unidecode==1.3 ; python_version >= "3.10" and python_version < "4.0" text-unidecode==1.3 ; python_version >= "3.10" and python_version < "4.0"
tomli==2.2.1 ; python_version >= "3.10" and python_version < "3.11" tomli==2.2.1 ; python_version == "3.10"
tomlkit==0.13.2 ; python_version >= "3.10" and python_version < "4.0" tomlkit==0.13.2 ; python_version >= "3.10" and python_version < "4.0"
tortoise-orm[asyncpg]==0.20.0 ; python_version >= "3.10" and python_version < "4.0" tortoise-orm[asyncpg]==0.20.0 ; 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.2.3 ; python_version >= "3.10" and python_version < "4.0" urllib3==2.3.0 ; python_version >= "3.10" and python_version < "4.0"
uvicorn[standard]==0.32.1 ; python_version >= "3.10" and python_version < "4.0" uvicorn[standard]==0.34.0 ; python_version >= "3.10" and python_version < "4.0"
uvloop==0.21.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0" uvloop==0.21.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0"
virtualenv==20.28.0 ; 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

@ -3,10 +3,6 @@ import os
import re import re
import nonebot import nonebot
# from nonebot.adapters.discord import Adapter as DiscordAdapter
from nonebot.adapters.dodo import Adapter as DoDoAdapter
from nonebot.adapters.kaiheila import Adapter as KaiheilaAdapter
from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter
from nonebot.log import logger from nonebot.log import logger
@ -17,8 +13,6 @@ from zhenxun.services.db_context import disconnect, init
driver = nonebot.get_driver() driver = nonebot.get_driver()
driver.register_adapter(OneBotV11Adapter) driver.register_adapter(OneBotV11Adapter)
driver.register_adapter(KaiheilaAdapter)
driver.register_adapter(DoDoAdapter)
driver.on_startup(init) driver.on_startup(init)

View File

@ -1,3 +1,4 @@
from collections import namedtuple
from collections.abc import Callable from collections.abc import Callable
from pathlib import Path from pathlib import Path
import platform import platform
@ -25,6 +26,40 @@ cpuinfo_get_cpu_info = {"brand_raw": "Intel(R) Core(TM) i7-10700K"}
def init_mocker(mocker: MockerFixture, tmp_path: Path): def init_mocker(mocker: MockerFixture, tmp_path: Path):
mock_psutil = mocker.patch("zhenxun.builtin_plugins.check.data_source.psutil") mock_psutil = mocker.patch("zhenxun.builtin_plugins.check.data_source.psutil")
# Define namedtuples for complex return values
CpuFreqs = namedtuple("CpuFreqs", ["current"]) # noqa: PYI024
VirtualMemoryInfo = namedtuple("VirtualMemoryInfo", ["used", "total", "percent"]) # noqa: PYI024
SwapInfo = namedtuple("SwapInfo", ["used", "total", "percent"]) # noqa: PYI024
DiskUsage = namedtuple("DiskUsage", ["used", "total", "free", "percent"]) # noqa: PYI024
# Set specific return values for psutil methods
mock_psutil.cpu_percent.return_value = 1.0 # CPU 使用率
mock_psutil.cpu_freq.return_value = CpuFreqs(current=0.0) # CPU 频率
mock_psutil.cpu_count.return_value = 1 # CPU 核心数
# Memory Info
mock_psutil.virtual_memory.return_value = VirtualMemoryInfo(
used=1 * 1024**3, # 1 GB in bytes for used memory
total=1 * 1024**3, # 1 GB in bytes for total memory
percent=100.0, # 100% of memory used
)
# Swap Info
mock_psutil.swap_memory.return_value = SwapInfo(
used=1 * 1024**3, # 1 GB in bytes for used swap space
total=1 * 1024**3, # 1 GB in bytes for total swap space
percent=100.0, # 100% of swap space used
)
# Disk Usage
mock_psutil.disk_usage.return_value = DiskUsage(
used=1 * 1024**3, # 1 GB in bytes for used disk space
total=1 * 1024**3, # 1 GB in bytes for total disk space
free=0, # No free space
percent=100.0, # 100% of disk space used
)
mock_cpuinfo = mocker.patch("zhenxun.builtin_plugins.check.data_source.cpuinfo") mock_cpuinfo = mocker.patch("zhenxun.builtin_plugins.check.data_source.cpuinfo")
mock_cpuinfo.get_cpu_info.return_value = cpuinfo_get_cpu_info mock_cpuinfo.get_cpu_info.return_value = cpuinfo_get_cpu_info
@ -95,19 +130,22 @@ async def test_check(
) )
ctx.receive_event(bot=bot, event=event) ctx.receive_event(bot=bot, event=event)
ctx.should_ignore_rule(_self_check_matcher) ctx.should_ignore_rule(_self_check_matcher)
mock_template_to_pic.assert_awaited_once_with(
template_path=str((mock_template_path_new / "check").absolute()), data = {
template_name="main.html", "cpu_info": f"{mock_psutil.cpu_percent.return_value}% "
templates={ + f"- {mock_psutil.cpu_freq.return_value.current}Ghz "
"data": { + f"[{mock_psutil.cpu_count.return_value} core]",
"cpu_info": "1.0% - 1.0Ghz [1 core]", "cpu_process": mock_psutil.cpu_percent.return_value,
"cpu_process": 1.0, "ram_info": f"{round(mock_psutil.virtual_memory.return_value.used / (1024 ** 3), 1)}" # noqa: E501
"ram_info": "1.0 / 1.0 GB", + f" / {round(mock_psutil.virtual_memory.return_value.total / (1024 ** 3), 1)}"
"ram_process": 100.0, + " GB",
"swap_info": "1.0 / 1.0 GB", "ram_process": mock_psutil.virtual_memory.return_value.percent,
"swap_process": 100.0, "swap_info": f"{round(mock_psutil.swap_memory.return_value.used / (1024 ** 3), 1)}" # noqa: E501
"disk_info": "1.0 / 1.0 GB", + f" / {round(mock_psutil.swap_memory.return_value.total / (1024 ** 3), 1)} GB",
"disk_process": 100.0, "swap_process": mock_psutil.swap_memory.return_value.percent,
"disk_info": f"{round(mock_psutil.disk_usage.return_value.used / (1024 ** 3), 1)}" # noqa: E501
+ f" / {round(mock_psutil.disk_usage.return_value.total / (1024 ** 3), 1)} GB",
"disk_process": mock_psutil.disk_usage.return_value.percent,
"brand_raw": cpuinfo_get_cpu_info["brand_raw"], "brand_raw": cpuinfo_get_cpu_info["brand_raw"],
"baidu": "red", "baidu": "red",
"google": "red", "google": "red",
@ -116,7 +154,11 @@ async def test_check(
"plugin_count": len(nonebot.get_loaded_plugins()), "plugin_count": len(nonebot.get_loaded_plugins()),
"nickname": BotConfig.self_nickname, "nickname": BotConfig.self_nickname,
} }
},
mock_template_to_pic.assert_awaited_once_with(
template_path=str((mock_template_path_new / "check").absolute()),
template_name="main.html",
templates={"data": data},
pages={ pages={
"viewport": {"width": 195, "height": 750}, "viewport": {"width": 195, "height": 750},
"base_url": f"file://{mock_template_path_new.absolute()}", "base_url": f"file://{mock_template_path_new.absolute()}",

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

@ -12,7 +12,7 @@ from pytest_asyncio import is_async_test
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from respx import MockRouter from respx import MockRouter
from tests.config import BotId, UserId from tests.config import BotId, GroupId, UserId
nonebot.load_plugin("nonebot_plugin_session") nonebot.load_plugin("nonebot_plugin_session")
@ -47,7 +47,7 @@ def pytest_configure(config: pytest.Config) -> None:
}, },
"host": "127.0.0.1", "host": "127.0.0.1",
"port": 8080, "port": 8080,
"log_level": "DEBUG", "log_level": "INFO",
} }
@ -60,12 +60,41 @@ def _init_bot(nonebug_init: None):
nonebot.load_plugin("nonebot_plugin_alconna") nonebot.load_plugin("nonebot_plugin_alconna")
nonebot.load_plugin("nonebot_plugin_apscheduler") nonebot.load_plugin("nonebot_plugin_apscheduler")
nonebot.load_plugin("nonebot_plugin_userinfo")
nonebot.load_plugin("nonebot_plugin_htmlrender") nonebot.load_plugin("nonebot_plugin_htmlrender")
nonebot.load_plugins("zhenxun/builtin_plugins") nonebot.load_plugins("zhenxun/builtin_plugins")
nonebot.load_plugins("zhenxun/plugins") nonebot.load_plugins("zhenxun/plugins")
# 手动缓存 uninfo 所需信息
from nonebot_plugin_uninfo import (
Scene,
SceneType,
Session,
SupportAdapter,
SupportScope,
User,
)
from nonebot_plugin_uninfo.adapters.onebot11.main import fetcher as onebot11_fetcher
from nonebot_plugin_uninfo.adapters.onebot12.main import fetcher as onebot12_fetcher
onebot11_fetcher.session_cache = {
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
self_id="test",
adapter=SupportAdapter.onebot11,
scope=SupportScope.qq_client,
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
user=User(str(UserId.SUPERUSER)),
),
}
onebot12_fetcher.session_cache = {
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
self_id="test",
adapter=SupportAdapter.onebot12,
scope=SupportScope.qq_client,
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
user=User(str(UserId.SUPERUSER)),
),
}
@pytest.fixture @pytest.fixture
async def app(app: App, tmp_path: Path, mocker: MockerFixture): async def app(app: App, tmp_path: Path, mocker: MockerFixture):

View File

@ -33,5 +33,5 @@ __plugin_meta__ = PluginMetadata(
检测b站 检测b站
bil_logout 12345<-(退出登录的b站uid通过检测b站获取) bil_logout 12345<-(退出登录的b站uid通过检测b站获取)
""", """,
).dict(), ).to_dict(),
) )

View File

@ -20,5 +20,5 @@ __plugin_meta__ = PluginMetadata(
extra=PluginExtraData( extra=PluginExtraData(
author="xuanerwa", author="xuanerwa",
version="0.7", version="0.7",
).dict(), ).to_dict(),
) )

View File

@ -13,5 +13,5 @@ __plugin_meta__ = PluginMetadata(
extra=PluginExtraData( extra=PluginExtraData(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
).dict(), ).to_dict(),
) )

View File

@ -14,5 +14,5 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
menu_type="一些工具", menu_type="一些工具",
).dict(), ).to_dict(),
) )

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

@ -19,7 +19,7 @@ __plugin_meta__ = PluginMetadata(
指令 指令
关于 关于
""".strip(), """.strip(),
extra=PluginExtraData(author="HibiKier", version="0.1", menu_type="其他").dict(), extra=PluginExtraData(author="HibiKier", version="0.1", menu_type="其他").to_dict(),
) )

View File

@ -33,7 +33,7 @@ __plugin_meta__ = PluginMetadata(
default_value="zhenxun", default_value="zhenxun",
) )
], ],
).dict(), ).to_dict(),
) )
_matcher = on_alconna( _matcher = on_alconna(

View File

@ -15,7 +15,8 @@ async def get_task() -> dict[str, str] | None:
return { return {
"name": "被动技能", "name": "被动技能",
"description": "控制群组中的被动技能状态", "description": "控制群组中的被动技能状态",
"usage": "通过 开启/关闭群被动 来控制群被<br>----------<br>" "usage": "通过 开启/关闭群被动 来控制群被动 <br>"
+ " 示例:开启/关闭群被动早晚安 <br> ---------- <br> "
+ "<br>".join([task.name for task in task_list]), + "<br>".join([task.name for task in task_list]),
} }
return None return None

View File

@ -27,7 +27,7 @@ __plugin_meta__ = PluginMetadata(
default_value=5, default_value=5,
) )
], ],
).dict(), ).to_dict(),
) )

View File

@ -78,7 +78,7 @@ __plugin_meta__ = PluginMetadata(
type=int, type=int,
) )
], ],
).dict(), ).to_dict(),
) )

View File

@ -105,7 +105,7 @@ class BanManage:
if idx: if idx:
ban_data = await BanConsole.get_or_none(id=idx) ban_data = await BanConsole.get_or_none(id=idx)
if not ban_data: if not ban_data:
return False, "该用户/群组不在黑名单中不足捏..." return False, "该用户/群组不在黑名单中捏..."
if ban_data.ban_level > user_level: if ban_data.ban_level > user_level:
return False, "unBan权限等级不足捏..." return False, "unBan权限等级不足捏..."
await ban_data.delete() await ban_data.delete()

View File

@ -30,7 +30,7 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.SUPER_AND_ADMIN, plugin_type=PluginType.SUPER_AND_ADMIN,
admin_level=1, admin_level=1,
).dict(), ).to_dict(),
) )

View File

@ -23,7 +23,7 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.SUPER_AND_ADMIN, plugin_type=PluginType.SUPER_AND_ADMIN,
admin_level=1, admin_level=1,
).dict(), ).to_dict(),
) )

View File

@ -80,7 +80,7 @@ __plugin_meta__ = PluginMetadata(
type=int, type=int,
) )
], ],
).dict(), ).to_dict(),
) )

View File

@ -1,3 +1,5 @@
import os
from zhenxun.configs.path_config import DATA_PATH, IMAGE_PATH from zhenxun.configs.path_config import DATA_PATH, IMAGE_PATH
from zhenxun.models.group_console import GroupConsole from zhenxun.models.group_console import GroupConsole
from zhenxun.models.plugin_info import PluginInfo from zhenxun.models.plugin_info import PluginInfo
@ -14,9 +16,9 @@ GROUP_HELP_PATH = DATA_PATH / "group_help"
def delete_help_image(gid: str | None = None): def delete_help_image(gid: str | None = None):
"""删除帮助图片""" """删除帮助图片"""
if gid: if gid:
file = GROUP_HELP_PATH / f"{gid}.png" for file in os.listdir(GROUP_HELP_PATH):
if file.exists(): if file.startswith(f"{gid}"):
file.unlink() os.remove(GROUP_HELP_PATH / file)
else: else:
if HELP_FILE.exists(): if HELP_FILE.exists():
HELP_FILE.unlink() HELP_FILE.unlink()

View File

@ -57,7 +57,7 @@ __plugin_meta__ = PluginMetadata(
default_value=2, default_value=2,
) )
], ],
).dict(), ).to_dict(),
) )
_matcher = on_command( _matcher = on_command(
@ -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()
def __migrate():
"""首次数据迁移"""
old_file = DATA_PATH / "custom_welcome_msg" / "custom_welcome_msg.json" old_file = DATA_PATH / "custom_welcome_msg" / "custom_welcome_msg.json"
if old_file.exists(): 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,7 +56,10 @@ def migrate(path: Path):
参数: 参数:
path: 路径 path: 路径
""" """
__migrate()
text_file = path / "text.json" text_file = path / "text.json"
if not text_file.exists():
return
with text_file.open(encoding="utf8") as f: with text_file.open(encoding="utf8") as f:
json_data = json.load(f) json_data = json.load(f)
new_data = {} new_data = {}
@ -206,6 +212,8 @@ class Manager:
返回: 返回:
list: 消息内容 list: 消息内容
""" """
if not session.group:
return None
json_data = cls.__get_data(session) json_data = cls.__get_data(session)
if not json_data: if not json_data:
return None return None
@ -244,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

@ -47,7 +47,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
_matcher = on_alconna( _matcher = on_alconna(

View File

@ -29,7 +29,7 @@ __plugin_meta__ = PluginMetadata(
type=bool, type=bool,
) )
], ],
).dict(), ).to_dict(),
) )
@ -39,7 +39,6 @@ def rule(message: UniMsg) -> bool:
chat_history = on_message(rule=rule, priority=1, block=False) chat_history = on_message(rule=rule, priority=1, block=False)
TEMP_LIST = [] TEMP_LIST = []
@ -70,14 +69,4 @@ async def _():
await ChatHistory.bulk_create(message_list) await ChatHistory.bulk_create(message_list)
logger.debug(f"批量添加聊天记录 {len(message_list)}", "定时任务") logger.debug(f"批量添加聊天记录 {len(message_list)}", "定时任务")
except Exception as e: except Exception as e:
logger.error("定时批量添加聊天记录", "定时任务", e=e) logger.warning("存储聊天记录失败", "chat_history", e=e)
# @test.handle()
# async def _(event: MessageEvent):
# print(await ChatHistory.get_user_msg(event.user_id, "private"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
# print(await ChatHistory.get_user_msg(event.user_id, "group"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
# print(await ChatHistory.get_group_msg(event.group_id))
# print(await ChatHistory.get_group_msg_count(event.group_id))

View File

@ -14,7 +14,7 @@ from nonebot_plugin_alconna import (
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
import pytz import pytz
from zhenxun.configs.utils import PluginExtraData from zhenxun.configs.utils import Command, PluginExtraData
from zhenxun.models.chat_history import ChatHistory from zhenxun.models.chat_history import ChatHistory
from zhenxun.models.group_member_info import GroupInfoUser from zhenxun.models.group_member_info import GroupInfoUser
from zhenxun.services.log import logger from zhenxun.services.log import logger
@ -45,7 +45,14 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.NORMAL, plugin_type=PluginType.NORMAL,
menu_type="数据统计", menu_type="数据统计",
).dict(), commands=[
Command(command="消息统计"),
Command(command="日消息统计"),
Command(command="周消息排行"),
Command(command="月消息排行"),
Command(command="年消息排行"),
],
).to_dict(),
) )

View File

@ -37,7 +37,7 @@ __plugin_meta__ = PluginMetadata(
default_value="mix", default_value="mix",
) )
], ],
).dict(), ).to_dict(),
) )

View File

@ -23,7 +23,7 @@ ARM_KEY = "aarch64"
@dataclass @dataclass
class CPUInfo: class CPUInfo:
core: int core: int | None
"""CPU 物理核心数""" """CPU 物理核心数"""
usage: float usage: float
"""CPU 占用百分比,取值范围(0,100]""" """CPU 占用百分比,取值范围(0,100]"""

View File

@ -13,7 +13,11 @@ from nonebot_plugin_alconna import (
) )
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from zhenxun.builtin_plugins.help._config import GROUP_HELP_PATH, SIMPLE_HELP_IMAGE from zhenxun.builtin_plugins.help._config import (
GROUP_HELP_PATH,
SIMPLE_DETAIL_HELP_IMAGE,
SIMPLE_HELP_IMAGE,
)
from zhenxun.configs.utils import PluginExtraData, RegisterConfig from zhenxun.configs.utils import PluginExtraData, RegisterConfig
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
@ -38,7 +42,7 @@ __plugin_meta__ = PluginMetadata(
default_value="zhenxun", default_value="zhenxun",
) )
], ],
).dict(), ).to_dict(),
) )
@ -47,6 +51,7 @@ _matcher = on_alconna(
"功能", "功能",
Args["name?", str], Args["name?", str],
Option("-s|--superuser", action=store_true, help_text="超级用户帮助"), Option("-s|--superuser", action=store_true, help_text="超级用户帮助"),
Option("-d|--detail", action=store_true, help_text="详细帮助"),
), ),
aliases={"help", "帮助", "菜单"}, aliases={"help", "帮助", "菜单"},
rule=to_me(), rule=to_me(),
@ -55,12 +60,21 @@ _matcher = on_alconna(
) )
_matcher.shortcut(
r"详细帮助",
command="功能",
arguments=["--detail"],
prefix=True,
)
@_matcher.handle() @_matcher.handle()
async def _( async def _(
bot: Bot, bot: Bot,
name: Match[str], name: Match[str],
session: Uninfo, session: Uninfo,
is_superuser: Query[bool] = AlconnaQuery("superuser.value", False), is_superuser: Query[bool] = AlconnaQuery("superuser.value", False),
is_detail: Query[bool] = AlconnaQuery("detail.value", False),
): ):
_is_superuser = is_superuser.result if is_superuser.available else False _is_superuser = is_superuser.result if is_superuser.available else False
if name.available: if name.available:
@ -74,11 +88,15 @@ async def _(
) )
logger.info(f"查看帮助详情: {name.result}", "帮助", session=session) logger.info(f"查看帮助详情: {name.result}", "帮助", session=session)
elif session.group and (gid := session.group.id): elif session.group and (gid := session.group.id):
_image_path = GROUP_HELP_PATH / f"{gid}.png" _image_path = GROUP_HELP_PATH / f"{gid}_{is_detail.result}.png"
if not _image_path.exists(): if not _image_path.exists():
await create_help_img(session, gid) result = await create_help_img(session, gid, is_detail.result)
await MessageUtils.build_message(_image_path).finish() await MessageUtils.build_message(_image_path).finish()
else: else:
if not SIMPLE_HELP_IMAGE.exists(): if is_detail.result:
await create_help_img(session, None) _image_path = SIMPLE_DETAIL_HELP_IMAGE
await MessageUtils.build_message(SIMPLE_HELP_IMAGE).finish() else:
_image_path = SIMPLE_HELP_IMAGE
if not _image_path.exists():
result = await create_help_img(session, None, is_detail.result)
await MessageUtils.build_message(_image_path).finish()

View File

@ -10,4 +10,8 @@ SIMPLE_HELP_IMAGE = IMAGE_PATH / "SIMPLE_HELP.png"
if SIMPLE_HELP_IMAGE.exists(): if SIMPLE_HELP_IMAGE.exists():
SIMPLE_HELP_IMAGE.unlink() SIMPLE_HELP_IMAGE.unlink()
SIMPLE_DETAIL_HELP_IMAGE = IMAGE_PATH / "SIMPLE_DETAIL_HELP.png"
if SIMPLE_DETAIL_HELP_IMAGE.exists():
SIMPLE_DETAIL_HELP_IMAGE.unlink()
base_config = Config.get("help") base_config = Config.get("help")

View File

@ -1,3 +1,5 @@
from pathlib import Path
import nonebot import nonebot
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
@ -7,7 +9,12 @@ from zhenxun.models.plugin_info import PluginInfo
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
from zhenxun.utils.image_utils import BuildImage, ImageTemplate from zhenxun.utils.image_utils import BuildImage, ImageTemplate
from ._config import GROUP_HELP_PATH, SIMPLE_HELP_IMAGE, base_config from ._config import (
GROUP_HELP_PATH,
SIMPLE_DETAIL_HELP_IMAGE,
SIMPLE_HELP_IMAGE,
base_config,
)
from .html_help import build_html_image from .html_help import build_html_image
from .normal_help import build_normal_image from .normal_help import build_normal_image
from .zhenxun_help import build_zhenxun_image from .zhenxun_help import build_zhenxun_image
@ -20,7 +27,9 @@ background = IMAGE_PATH / "background" / "0.png"
driver = nonebot.get_driver() driver = nonebot.get_driver()
async def create_help_img(session: Uninfo, group_id: str | None): async def create_help_img(
session: Uninfo, group_id: str | None, is_detail: bool
) -> Path:
"""生成帮助图片 """生成帮助图片
参数: 参数:
@ -31,14 +40,21 @@ async def create_help_img(session: Uninfo, group_id: str | None):
match help_type: match help_type:
case "html": case "html":
result = BuildImage.open(await build_html_image(group_id)) result = BuildImage.open(await build_html_image(group_id, is_detail))
case "zhenxun": case "zhenxun":
result = BuildImage.open(await build_zhenxun_image(session, group_id)) result = BuildImage.open(
await build_zhenxun_image(session, group_id, is_detail)
)
case _: case _:
result = await build_normal_image(group_id) result = await build_normal_image(group_id, is_detail)
if group_id:
save_path = GROUP_HELP_PATH / f"{group_id}.png" if group_id else SIMPLE_HELP_IMAGE save_path = GROUP_HELP_PATH / f"{group_id}_{is_detail}.png"
elif is_detail:
save_path = SIMPLE_DETAIL_HELP_IMAGE
else:
save_path = SIMPLE_HELP_IMAGE
await result.save(save_path) await result.save(save_path)
return save_path
async def get_user_allow_help(user_id: str) -> list[PluginType]: async def get_user_allow_help(user_id: str) -> list[PluginType]:

View File

@ -26,11 +26,14 @@ async def sort_type() -> dict[str, list[PluginInfo]]:
return sort_data return sort_data
async def classify_plugin(group_id: str | None, handle: Callable) -> dict[str, list]: async def classify_plugin(
group_id: str | None, is_detail: bool, handle: Callable
) -> dict[str, list]:
"""对插件进行分类并判断状态 """对插件进行分类并判断状态
参数: 参数:
group_id: 群组id group_id: 群组id
is_detail: 是否详细帮助
返回: 返回:
dict[str, list[Item]]: 分类插件数据 dict[str, list[Item]]: 分类插件数据
@ -42,5 +45,5 @@ async def classify_plugin(group_id: str | None, handle: Callable) -> dict[str, l
for plugin in value: for plugin in value:
if not classify.get(menu): if not classify.get(menu):
classify[menu] = [] classify[menu] = []
classify[menu].append(handle(plugin, group)) classify[menu].append(handle(plugin, group, is_detail))
return classify return classify

View File

@ -47,12 +47,15 @@ ICON2STR = {
} }
def __handle_item(plugin: PluginInfo, group: GroupConsole | None) -> Item: def __handle_item(
plugin: PluginInfo, group: GroupConsole | None, is_detail: bool
) -> Item:
"""构造Item """构造Item
参数: 参数:
plugin: PluginInfo plugin: PluginInfo
group: 群组 group: 群组
is_detail: 是否详细
返回: 返回:
Item: Item Item: Item
@ -116,13 +119,14 @@ def build_plugin_data(classify: dict[str, list[Item]]) -> list[dict[str, str]]:
return plugin_list return plugin_list
async def build_html_image(group_id: str | None) -> bytes: async def build_html_image(group_id: str | None, is_detail: bool) -> bytes:
"""构造HTML帮助图片 """构造HTML帮助图片
参数: 参数:
group_id: 群号 group_id: 群号
is_detail: 是否详细帮助
""" """
classify = await classify_plugin(group_id, __handle_item) classify = await classify_plugin(group_id, is_detail, __handle_item)
plugin_list = build_plugin_data(classify) plugin_list = build_plugin_data(classify)
return await template_to_pic( return await template_to_pic(
template_path=str((TEMPLATE_PATH / "menu").absolute()), template_path=str((TEMPLATE_PATH / "menu").absolute()),

View File

@ -9,11 +9,12 @@ from ._utils import sort_type
BACKGROUND_PATH = IMAGE_PATH / "background" / "help" / "simple_help" BACKGROUND_PATH = IMAGE_PATH / "background" / "help" / "simple_help"
async def build_normal_image(group_id: str | None) -> BuildImage: async def build_normal_image(group_id: str | None, is_detail: bool) -> BuildImage:
"""构造PIL帮助图片 """构造PIL帮助图片
参数: 参数:
group_id: 群号 group_id: 群号
is_detail: 详细帮助
""" """
image_list = [] image_list = []
font_size = 24 font_size = 24

View File

@ -1,9 +1,11 @@
import nonebot
from nonebot_plugin_htmlrender import template_to_pic from nonebot_plugin_htmlrender import template_to_pic
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from pydantic import BaseModel from pydantic import BaseModel
from zhenxun.configs.config import BotConfig from zhenxun.configs.config import BotConfig
from zhenxun.configs.path_config import TEMPLATE_PATH from zhenxun.configs.path_config import TEMPLATE_PATH
from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.group_console import GroupConsole from zhenxun.models.group_console import GroupConsole
from zhenxun.models.plugin_info import PluginInfo from zhenxun.models.plugin_info import PluginInfo
from zhenxun.utils.enum import BlockType from zhenxun.utils.enum import BlockType
@ -15,9 +17,11 @@ from ._utils import classify_plugin
class Item(BaseModel): class Item(BaseModel):
plugin_name: str plugin_name: str
"""插件名称""" """插件名称"""
commands: list[str]
"""插件命令"""
def __handle_item(plugin: PluginInfo, group: GroupConsole | None): def __handle_item(plugin: PluginInfo, group: GroupConsole | None, is_detail: bool):
"""构造Item """构造Item
参数: 参数:
@ -36,7 +40,12 @@ def __handle_item(plugin: PluginInfo, group: GroupConsole | None):
plugin.name = f"{plugin.name}(不可用)" plugin.name = f"{plugin.name}(不可用)"
elif group and f"{plugin.module}," in group.block_plugin: elif group and f"{plugin.module}," in group.block_plugin:
plugin.name = f"{plugin.name}(不可用)" plugin.name = f"{plugin.name}(不可用)"
return Item(plugin_name=f"{plugin.id}-{plugin.name}") commands = []
nb_plugin = nonebot.get_plugin_by_module_name(plugin.module_path)
if is_detail and nb_plugin and nb_plugin.metadata and nb_plugin.metadata.extra:
extra_data = PluginExtraData(**nb_plugin.metadata.extra)
commands = [cmd.command for cmd in extra_data.commands]
return Item(plugin_name=f"{plugin.id}-{plugin.name}", commands=commands)
def build_plugin_data(classify: dict[str, list[Item]]) -> list[dict[str, str]]: def build_plugin_data(classify: dict[str, list[Item]]) -> list[dict[str, str]]:
@ -123,18 +132,24 @@ def build_line_data(plugin_list: list[dict]) -> list[dict]:
return data return data
async def build_zhenxun_image(session: Uninfo, group_id: str | None) -> bytes: async def build_zhenxun_image(
session: Uninfo, group_id: str | None, is_detail: bool
) -> bytes:
"""构造真寻帮助图片 """构造真寻帮助图片
参数: 参数:
bot_id: bot_id bot_id: bot_id
group_id: 群号 group_id: 群号
is_detail: 是否详细帮助
""" """
classify = await classify_plugin(group_id, __handle_item) classify = await classify_plugin(group_id, is_detail, __handle_item)
plugin_list = build_plugin_data(classify) plugin_list = build_plugin_data(classify)
platform = PlatformUtils.get_platform(session) platform = PlatformUtils.get_platform(session)
bot_id = BotConfig.get_qbot_uid(session.self_id) or session.self_id bot_id = BotConfig.get_qbot_uid(session.self_id) or session.self_id
bot_ava = PlatformUtils.get_user_avatar_url(bot_id, platform) bot_ava = PlatformUtils.get_user_avatar_url(bot_id, platform)
width = int(637 * 1.5) if is_detail else 637
title_font = int(53 * 1.5) if is_detail else 53
tip_font = int(19 * 1.5) if is_detail else 19
return await template_to_pic( return await template_to_pic(
template_path=str((TEMPLATE_PATH / "ss_menu").absolute()), template_path=str((TEMPLATE_PATH / "ss_menu").absolute()),
template_name="main.html", template_name="main.html",
@ -142,10 +157,13 @@ async def build_zhenxun_image(session: Uninfo, group_id: str | None) -> bytes:
"data": { "data": {
"plugin_list": plugin_list, "plugin_list": plugin_list,
"ava": bot_ava, "ava": bot_ava,
"width": width,
"font_size": (title_font, tip_font),
"is_detail": is_detail,
} }
}, },
pages={ pages={
"viewport": {"width": 637, "height": 453}, "viewport": {"width": width, "height": 453},
"base_url": f"file://{TEMPLATE_PATH}", "base_url": f"file://{TEMPLATE_PATH}",
}, },
wait=2, wait=2,

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
@ -26,10 +27,25 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.DEPENDANT, plugin_type=PluginType.DEPENDANT,
menu_type="其他", menu_type="其他",
).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

@ -4,7 +4,7 @@ from nonebot_plugin_alconna import Alconna, Args, Arparma, At, Match, on_alconna
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from playwright.async_api import TimeoutError from playwright.async_api import TimeoutError
from zhenxun.configs.utils import PluginExtraData from zhenxun.configs.utils import Command, PluginExtraData
from zhenxun.models.group_member_info import GroupInfoUser from zhenxun.models.group_member_info import GroupInfoUser
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.depends import UserName from zhenxun.utils.depends import UserName
@ -20,7 +20,9 @@ __plugin_meta__ = PluginMetadata(
指令 指令
我的信息 ?[at] 我的信息 ?[at]
""".strip(), """.strip(),
extra=PluginExtraData(author="HibiKier", version="0.1").dict(), extra=PluginExtraData(
author="HibiKier", version="0.1", commands=[Command(command="我的信息")]
).to_dict(),
) )

View File

@ -145,7 +145,7 @@ async def get_user_info(
bytes: 图片数据 bytes: 图片数据
""" """
platform = PlatformUtils.get_platform(session) or "qq" platform = PlatformUtils.get_platform(session) or "qq"
ava_url = PlatformUtils.get_user_avatar_url(user_id, platform) ava_url = PlatformUtils.get_user_avatar_url(user_id, platform, session.self_id)
user = await UserConsole.get_user(user_id, platform) user = await UserConsole.get_user(user_id, platform)
level = await LevelUser.get_user_level(user_id, group_id) level = await LevelUser.get_user_level(user_id, group_id)
sign_level = 0 sign_level = 0

View File

@ -49,7 +49,7 @@ def _handle_config(plugin: Plugin, exists_module: list[str]):
arg_parser=reg_config.arg_parser, arg_parser=reg_config.arg_parser,
_override=False, _override=False,
) )
exists_module.append(f"{module}:{reg_config.key}") exists_module.append(f"{module}:{reg_config.key}".lower())
def _generate_simple_config(exists_module: list[str]): def _generate_simple_config(exists_module: list[str]):
@ -62,6 +62,7 @@ def _generate_simple_config(exists_module: list[str]):
# 读取用户配置 # 读取用户配置
_data = {} _data = {}
_tmp_data = {} _tmp_data = {}
exists_module += Config.add_module
if SIMPLE_CONFIG_FILE.exists(): if SIMPLE_CONFIG_FILE.exists():
_data = _yaml.load(SIMPLE_CONFIG_FILE.open(encoding="utf8")) _data = _yaml.load(SIMPLE_CONFIG_FILE.open(encoding="utf8"))
# 将简易配置文件的数据填充到配置文件 # 将简易配置文件的数据填充到配置文件
@ -71,7 +72,7 @@ def _generate_simple_config(exists_module: list[str]):
try: try:
if _data.get(module) and k in _data[module].keys(): if _data.get(module) and k in _data[module].keys():
Config.set_config(module, k, _data[module][k]) Config.set_config(module, k, _data[module][k])
if f"{module}:{k}" in exists_module: if f"{module}:{k}".lower() in exists_module:
_tmp_data[module][k] = Config.get_config(module, k) _tmp_data[module][k] = Config.get_config(module, k)
except AttributeError as e: except AttributeError as e:
raise AttributeError(f"{e}\n可能为config.yaml配置文件填写不规范") from e raise AttributeError(f"{e}\n可能为config.yaml配置文件填写不规范") from e

View File

@ -72,7 +72,10 @@ async def _handle_setting(
cost_gold=setting.cost_gold, cost_gold=setting.cost_gold,
plugin_type=extra_data.plugin_type, plugin_type=extra_data.plugin_type,
admin_level=extra_data.admin_level, admin_level=extra_data.admin_level,
is_show=extra_data.is_show,
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:

View File

@ -181,7 +181,7 @@ class Manager:
del temp_data["test"]["check_type"] del temp_data["test"]["check_type"]
else: else:
for v in temp_data: for v in temp_data:
temp_data[v] = temp_data[v].dict() temp_data[v] = temp_data[v].to_dict()
if check_type := temp_data[v].get("check_type"): if check_type := temp_data[v].get("check_type"):
temp_data[v]["check_type"] = str(check_type) temp_data[v]["check_type"] = str(check_type)
if watch_type := temp_data[v].get("watch_type"): if watch_type := temp_data[v].get("watch_type"):

View File

@ -7,11 +7,10 @@ from nonebot.params import Depends, RegexGroup
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot_plugin_alconna import Alconna, Option, on_alconna, store_true from nonebot_plugin_alconna import Alconna, Option, on_alconna, store_true
from nonebot_plugin_session import EventSession from nonebot_plugin_uninfo import Uninfo
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
from zhenxun.configs.config import BotConfig, Config from zhenxun.configs.config import BotConfig, Config
from zhenxun.configs.utils import PluginExtraData, RegisterConfig from zhenxun.configs.utils import Command, PluginExtraData, RegisterConfig
from zhenxun.models.ban_console import BanConsole from zhenxun.models.ban_console import BanConsole
from zhenxun.models.friend_user import FriendUser from zhenxun.models.friend_user import FriendUser
from zhenxun.models.group_member_info import GroupInfoUser from zhenxun.models.group_member_info import GroupInfoUser
@ -19,6 +18,7 @@ from zhenxun.services.log import logger
from zhenxun.utils.depends import UserName from zhenxun.utils.depends import UserName
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
from zhenxun.utils.platform import PlatformUtils
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="昵称系统", name="昵称系统",
@ -36,6 +36,11 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.NORMAL, plugin_type=PluginType.NORMAL,
menu_type="其他", menu_type="其他",
commands=[
Command(command="以后叫我 [昵称]"),
Command(command="全局昵称设置 [昵称]"),
Command(command=f"{BotConfig.self_nickname}我是谁"),
],
configs=[ configs=[
RegisterConfig( RegisterConfig(
key="BLACK_WORD", key="BLACK_WORD",
@ -46,7 +51,7 @@ __plugin_meta__ = PluginMetadata(
type=list[str], type=list[str],
) )
], ],
).dict(), ).to_dict(),
) )
_nickname_matcher = on_regex( _nickname_matcher = on_regex(
@ -119,7 +124,7 @@ def CheckNickname():
async def dependency( async def dependency(
bot: Bot, bot: Bot,
session: EventSession, session: Uninfo,
reg_group: tuple[Any, ...] = RegexGroup(), reg_group: tuple[Any, ...] = RegexGroup(),
): ):
black_word = Config.get_config("nickname", "BLACK_WORD") black_word = Config.get_config("nickname", "BLACK_WORD")
@ -129,7 +134,7 @@ def CheckNickname():
await MessageUtils.build_message("叫你空白?叫你虚空?叫你无名??").finish( await MessageUtils.build_message("叫你空白?叫你虚空?叫你无名??").finish(
at_sender=True at_sender=True
) )
if session.id1 in bot.config.superusers: if session.user.id in bot.config.superusers:
logger.debug( logger.debug(
f"超级用户设置昵称, 跳过合法检测: {name}", "昵称设置", session=session f"超级用户设置昵称, 跳过合法检测: {name}", "昵称设置", session=session
) )
@ -163,76 +168,73 @@ def CheckNickname():
@_nickname_matcher.handle(parameterless=[CheckNickname()]) @_nickname_matcher.handle(parameterless=[CheckNickname()])
async def _( async def _(
session: EventSession, session: Uninfo,
user_info: UserInfo = EventUserInfo(), uname: str = UserName(),
reg_group: tuple[Any, ...] = RegexGroup(), reg_group: tuple[Any, ...] = RegexGroup(),
): ):
if session.id1:
(name,) = reg_group (name,) = reg_group
if len(name) < 5 and random.random() < 0.3: if len(name) < 5 and random.random() < 0.3:
name = "~".join(name) name = "~".join(name)
if gid := session.id3 or session.id2: group_id = None
if session.group:
group_id = session.group.parent.id if session.group.parent else session.group.id
if group_id:
await GroupInfoUser.set_user_nickname( await GroupInfoUser.set_user_nickname(
session.id1, session.user.id,
gid, group_id,
name, name,
user_info.user_displayname uname,
or user_info.user_remark PlatformUtils.get_platform(session),
or user_info.user_name,
session.platform,
) )
logger.info(f"设置群昵称成功: {name}", "昵称设置", session=session) logger.info(f"设置群昵称成功: {name}", "昵称设置", session=session)
else: else:
await FriendUser.set_user_nickname( await FriendUser.set_user_nickname(
session.id1, session.user.id,
name, name,
user_info.user_displayname uname,
or user_info.user_remark PlatformUtils.get_platform(session),
or user_info.user_name,
session.platform,
) )
logger.info(f"设置私聊昵称成功: {name}", "昵称设置", session=session) logger.info(f"设置私聊昵称成功: {name}", "昵称设置", session=session)
await MessageUtils.build_message(random.choice(CALL_NAME).format(name)).finish( await MessageUtils.build_message(random.choice(CALL_NAME).format(name)).finish(
reply_to=True reply_to=True
) )
await MessageUtils.build_message("用户id为空...").send()
@_global_nickname_matcher.handle(parameterless=[CheckNickname()]) @_global_nickname_matcher.handle(parameterless=[CheckNickname()])
async def _( async def _(
session: EventSession, session: Uninfo,
nickname: str = UserName(), nickname: str = UserName(),
reg_group: tuple[Any, ...] = RegexGroup(), reg_group: tuple[Any, ...] = RegexGroup(),
): ):
if session.id1:
(name,) = reg_group (name,) = reg_group
await FriendUser.set_user_nickname( await FriendUser.set_user_nickname(
session.id1, session.user.id,
name, name,
nickname, nickname,
session.platform, PlatformUtils.get_platform(session),
) )
await GroupInfoUser.filter(user_id=session.id1).update(nickname=name) await GroupInfoUser.filter(user_id=session.user.id).update(nickname=name)
logger.info(f"设置全局昵称成功: {name}", "设置全局昵称", session=session) logger.info(f"设置全局昵称成功: {name}", "设置全局昵称", session=session)
await MessageUtils.build_message(random.choice(CALL_NAME).format(name)).finish( await MessageUtils.build_message(random.choice(CALL_NAME).format(name)).finish(
reply_to=True reply_to=True
) )
await MessageUtils.build_message("用户id为空...").send()
@_matcher.assign("name") @_matcher.assign("name")
async def _(session: EventSession, user_info: UserInfo = EventUserInfo()): async def _(session: Uninfo, uname: str = UserName()):
if session.id1: group_id = None
if gid := session.id3 or session.id2: if session.group:
nickname = await GroupInfoUser.get_user_nickname(session.id1, gid) group_id = session.group.parent.id if session.group.parent else session.group.id
card = user_info.user_displayname or user_info.user_name if group_id:
nickname = await GroupInfoUser.get_user_nickname(session.user.id, group_id)
card = uname
else: else:
nickname = await FriendUser.get_user_nickname(session.id1) nickname = await FriendUser.get_user_nickname(session.user.id)
card = user_info.user_name card = uname
if nickname: if nickname:
await MessageUtils.build_message( await MessageUtils.build_message(random.choice(REMIND).format(nickname)).finish(
random.choice(REMIND).format(nickname) reply_to=True
).finish(reply_to=True) )
else: else:
await MessageUtils.build_message( await MessageUtils.build_message(
random.choice( random.choice(
@ -244,29 +246,28 @@ async def _(session: EventSession, user_info: UserInfo = EventUserInfo()):
] ]
).format(card) ).format(card)
).finish(reply_to=True) ).finish(reply_to=True)
await MessageUtils.build_message("用户id为空...").send()
@_matcher.assign("cancel") @_matcher.assign("cancel")
async def _(bot: Bot, session: EventSession, user_info: UserInfo = EventUserInfo()): async def _(bot: Bot, session: Uninfo):
if session.id1: group_id = None
gid = session.id3 or session.id2 if session.group:
if gid: group_id = session.group.parent.id if session.group.parent else session.group.id
nickname = await GroupInfoUser.get_user_nickname(session.id1, gid) if group_id:
nickname = await GroupInfoUser.get_user_nickname(session.user.id, group_id)
else: else:
nickname = await FriendUser.get_user_nickname(session.id1) nickname = await FriendUser.get_user_nickname(session.user.id)
if nickname: if nickname:
await MessageUtils.build_message( await MessageUtils.build_message(random.choice(CANCEL).format(nickname)).send(
random.choice(CANCEL).format(nickname) reply_to=True
).send(reply_to=True) )
if gid: if group_id:
await GroupInfoUser.set_user_nickname(session.id1, gid, "") await GroupInfoUser.set_user_nickname(session.user.id, group_id, "")
else: else:
await FriendUser.set_user_nickname(session.id1, "") await FriendUser.set_user_nickname(session.user.id, "")
await BanConsole.ban(session.id1, gid, 9, 60, bot.self_id) await BanConsole.ban(session.user.id, group_id, 9, 60, bot.self_id)
return return
else: else:
await MessageUtils.build_message("你在做梦吗?你没有昵称啊").finish( await MessageUtils.build_message("你在做梦吗?你没有昵称啊").finish(
reply_to=True reply_to=True
) )
await MessageUtils.build_message("用户id为空...").send()

View File

@ -16,7 +16,9 @@ except ImportError:
try: try:
from nonebot.adapters.qq import Bot # noqa: F401 from nonebot.adapters.qq import ( # noqa: F401 # pyright: ignore [reportMissingImports]
Bot,
)
nonebot.load_plugins(str((path / "qq_api").resolve())) nonebot.load_plugins(str((path / "qq_api").resolve()))
except ImportError: except ImportError:

View File

@ -84,7 +84,7 @@ __plugin_meta__ = PluginMetadata(
default_status=False, default_status=False,
), ),
], ],
).dict(), ).to_dict(),
) )
@ -116,19 +116,19 @@ async def _(
session: Uninfo, session: Uninfo,
event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent, event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent,
): ):
user_id = str(event.user_id) if session.user.id == bot.self_id:
group_id = str(event.group_id)
if user_id == bot.self_id:
"""新成员为bot本身""" """新成员为bot本身"""
group, _ = await GroupConsole.get_or_create( group, _ = await GroupConsole.get_or_create(
group_id=group_id, channel_id__isnull=True group_id=str(event.group_id), channel_id__isnull=True
) )
try: try:
await GroupManager.add_bot(bot, str(event.operator_id), group_id, group) await GroupManager.add_bot(
bot, str(event.operator_id), str(event.group_id), group
)
except ForceAddGroupError as e: except ForceAddGroupError as e:
await PlatformUtils.send_superuser(bot, e.get_info()) await PlatformUtils.send_superuser(bot, e.get_info())
else: else:
await GroupManager.add_user(session, bot, user_id, group_id) await GroupManager.add_user(session, bot)
@group_decrease_handle.handle() @group_decrease_handle.handle()

View File

@ -4,6 +4,7 @@ from pathlib import Path
import random import random
from nonebot.adapters import Bot from nonebot.adapters import Bot
from nonebot.exception import ActionFailed
from nonebot_plugin_alconna import At, UniMessage from nonebot_plugin_alconna import At, UniMessage
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
import ujson as json import ujson as json
@ -217,11 +218,8 @@ class GroupManager:
msg_list.insert(0, At("user", user_id)) msg_list.insert(0, At("user", user_id))
logger.info("发送群欢迎消息...", "入群检测", session=session) logger.info("发送群欢迎消息...", "入群检测", session=session)
if msg_list: if msg_list:
await MessageUtils.build_message(msg_list).send() # type: ignore await MessageUtils.build_message(msg_list).finish() # type: ignore
else: image = DEFAULT_IMAGE_PATH / random.choice(os.listdir(DEFAULT_IMAGE_PATH))
image = DEFAULT_IMAGE_PATH / random.choice(
os.listdir(DEFAULT_IMAGE_PATH)
)
await MessageUtils.build_message( await MessageUtils.build_message(
[ [
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)", "新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
@ -230,20 +228,35 @@ class GroupManager:
).send() ).send()
@classmethod @classmethod
async def add_user(cls, session: Uninfo, bot: Bot, user_id: str, group_id: str): async def add_user(cls, session: Uninfo, bot: Bot):
"""拉入用户 """拉入用户
参数: 参数:
session: Uninfo
bot: Bot bot: Bot
user_id: 用户id
group_id: 群组id
""" """
user_id = session.user.id
group_id = ""
if session.group:
if session.group.parent:
group_id = session.group.parent.id
else:
group_id = session.group.id
join_time = datetime.now() join_time = datetime.now()
user_info = await bot.get_group_member_info(group_id=group_id, user_id=user_id) try:
user_info = await bot.get_group_member_info(
group_id=int(group_id), user_id=int(user_id), no_cache=True
)
except ActionFailed as e:
logger.warning("获取用户信息识别...", e=e)
user_info = {"user_id": user_id, "group_id": group_id, "nickname": ""}
await GroupInfoUser.update_or_create( await GroupInfoUser.update_or_create(
user_id=str(user_info["user_id"]), user_id=str(user_info["user_id"]),
group_id=str(user_info["group_id"]), group_id=str(user_info["group_id"]),
defaults={"user_name": user_info["nickname"], "user_join_time": join_time}, defaults={
"user_name": user_info["nickname"],
"user_join_time": join_time,
},
) )
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
if not await CommonUtils.task_is_block( if not await CommonUtils.task_is_block(
@ -312,10 +325,13 @@ class GroupManager:
group_id=group_id, group_id=group_id,
) )
if sub_type == "kick": if sub_type == "kick":
if operator_id != "0":
operator = await bot.get_group_member_info( operator = await bot.get_group_member_info(
user_id=int(operator_id), group_id=int(group_id) user_id=int(operator_id), group_id=int(group_id)
) )
operator_name = operator["card"] or operator["nickname"] operator_name = operator["card"] or operator["nickname"]
else:
operator_name = ""
return f"{user_name}{operator_name} 送走了." return f"{user_name}{operator_name} 送走了."
elif sub_type == "leave": elif sub_type == "leave":
return f"{user_name}离开了我们..." return f"{user_name}离开了我们..."

View File

@ -7,6 +7,7 @@ from zhenxun.configs.utils import PluginExtraData
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
from zhenxun.utils.utils import is_number
from .data_source import ShopManage from .data_source import ShopManage
@ -25,16 +26,16 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
_matcher = on_alconna( _matcher = on_alconna(
Alconna( Alconna(
"插件商店", "插件商店",
Subcommand("add", Args["plugin_id", int | str]), Subcommand("add", Args["plugin_id", str]),
Subcommand("remove", Args["plugin_id", int | str]), Subcommand("remove", Args["plugin_id", str]),
Subcommand("search", Args["plugin_name_or_author", str]), Subcommand("search", Args["plugin_name_or_author", str]),
Subcommand("update", Args["plugin_id", int | str]), Subcommand("update", Args["plugin_id", str]),
Subcommand("update_all"), Subcommand("update_all"),
), ),
permission=SUPERUSER, permission=SUPERUSER,
@ -43,14 +44,14 @@ _matcher = on_alconna(
) )
_matcher.shortcut( _matcher.shortcut(
r"添加插件", r"(添加|安装)插件",
command="插件商店", command="插件商店",
arguments=["add", "{%0}"], arguments=["add", "{%0}"],
prefix=True, prefix=True,
) )
_matcher.shortcut( _matcher.shortcut(
r"移除插件", r"(移除|卸载)插件",
command="插件商店", command="插件商店",
arguments=["remove", "{%0}"], arguments=["remove", "{%0}"],
prefix=True, prefix=True,
@ -90,12 +91,12 @@ async def _(session: EventSession):
@_matcher.assign("add") @_matcher.assign("add")
async def _(session: EventSession, plugin_id: int | str): async def _(session: EventSession, plugin_id: str):
try: try:
if isinstance(plugin_id, str): if is_number(plugin_id):
await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send()
else:
await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send() await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send()
else:
await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send()
result = await ShopManage.add_plugin(plugin_id) result = await ShopManage.add_plugin(plugin_id)
except Exception as e: except Exception as e:
logger.error(f"添加插件 Id: {plugin_id}失败", "插件商店", session=session, e=e) logger.error(f"添加插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
@ -107,7 +108,7 @@ async def _(session: EventSession, plugin_id: int | str):
@_matcher.assign("remove") @_matcher.assign("remove")
async def _(session: EventSession, plugin_id: int | str): async def _(session: EventSession, plugin_id: str):
try: try:
result = await ShopManage.remove_plugin(plugin_id) result = await ShopManage.remove_plugin(plugin_id)
except Exception as e: except Exception as e:
@ -138,12 +139,12 @@ async def _(session: EventSession, plugin_name_or_author: str):
@_matcher.assign("update") @_matcher.assign("update")
async def _(session: EventSession, plugin_id: int | str): async def _(session: EventSession, plugin_id: str):
try: try:
if isinstance(plugin_id, str): if is_number(plugin_id):
await MessageUtils.build_message(f"正在更新插件 Module: {plugin_id}").send()
else:
await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send() await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send()
else:
await MessageUtils.build_message(f"正在更新插件 Module: {plugin_id}").send()
result = await ShopManage.update_plugin(plugin_id) result = await ShopManage.update_plugin(plugin_id)
except Exception as e: except Exception as e:
logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e) logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)

View File

@ -14,6 +14,7 @@ from zhenxun.utils.github_utils import GithubUtils
from zhenxun.utils.github_utils.models import RepoAPI from zhenxun.utils.github_utils.models import RepoAPI
from zhenxun.utils.http_utils import AsyncHttpx from zhenxun.utils.http_utils import AsyncHttpx
from zhenxun.utils.image_utils import BuildImage, ImageTemplate, RowStyle from zhenxun.utils.image_utils import BuildImage, ImageTemplate, RowStyle
from zhenxun.utils.utils import is_number
from .config import BASE_PATH, DEFAULT_GITHUB_URL, EXTRA_GITHUB_URL from .config import BASE_PATH, DEFAULT_GITHUB_URL, EXTRA_GITHUB_URL
@ -50,7 +51,7 @@ def install_requirement(plugin_path: Path):
try: try:
result = subprocess.run( result = subprocess.run(
["pip", "install", "-r", str(existing_requirements)], ["poetry", "run", "pip", "install", "-r", str(existing_requirements)],
check=True, check=True,
capture_output=True, capture_output=True,
text=True, text=True,
@ -79,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)
@ -175,7 +181,7 @@ class ShopManage:
) )
@classmethod @classmethod
async def add_plugin(cls, plugin_id: int | str) -> str: async def add_plugin(cls, plugin_id: str) -> str:
"""添加插件 """添加插件
参数: 参数:
@ -217,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:
@ -231,8 +241,9 @@ class ShopManage:
raise ValueError("所有API获取插件文件失败请检查网络连接") raise ValueError("所有API获取插件文件失败请检查网络连接")
if module_path == ".": if module_path == ".":
module_path = "" module_path = ""
replace_module_path = module_path.replace(".", "/")
files = repo_api.get_files( files = repo_api.get_files(
module_path=module_path.replace(".", "/") + ("" if is_dir else ".py"), module_path=replace_module_path + ("" if is_dir else ".py"),
is_dir=is_dir, is_dir=is_dir,
) )
download_urls = [await repo_info.get_raw_download_urls(file) for file in files] download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
@ -247,8 +258,13 @@ class ShopManage:
else: else:
# 安装依赖 # 安装依赖
plugin_path = base_path / "/".join(module_path.split(".")) plugin_path = base_path / "/".join(module_path.split("."))
req_files = repo_api.get_files(REQ_TXT_FILE_STRING, False) try:
req_files.extend(repo_api.get_files("requirement.txt", False)) req_files = repo_api.get_files(
f"{replace_module_path}/{REQ_TXT_FILE_STRING}", False
)
req_files.extend(
repo_api.get_files(f"{replace_module_path}/requirement.txt", False)
)
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理") logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
req_download_urls = [ req_download_urls = [
await repo_info.get_raw_download_urls(file) for file in req_files await repo_info.get_raw_download_urls(file) for file in req_files
@ -264,11 +280,13 @@ class ShopManage:
raise Exception("插件依赖文件下载失败") raise Exception("插件依赖文件下载失败")
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理") logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
install_requirement(plugin_path) install_requirement(plugin_path)
except ValueError as e:
logger.warning("未获取到依赖文件路径...", e=e)
return True return True
raise Exception("插件下载失败") raise Exception("插件下载失败...")
@classmethod @classmethod
async def remove_plugin(cls, plugin_id: int | str) -> str: async def remove_plugin(cls, plugin_id: str) -> str:
"""移除插件 """移除插件
参数: 参数:
@ -344,7 +362,7 @@ class ShopManage:
) )
@classmethod @classmethod
async def update_plugin(cls, plugin_id: int | str) -> str: async def update_plugin(cls, plugin_id: str) -> str:
"""更新插件 """更新插件
参数: 参数:
@ -441,12 +459,13 @@ class ShopManage:
) )
@classmethod @classmethod
async def _resolve_plugin_key(cls, plugin_id: int | str) -> str: async def _resolve_plugin_key(cls, plugin_id: str) -> str:
data: dict[str, StorePluginInfo] = await cls.get_data() data: dict[str, StorePluginInfo] = await cls.get_data()
if isinstance(plugin_id, int): if is_number(plugin_id):
if plugin_id < 0 or plugin_id >= len(data): idx = int(plugin_id)
if idx < 0 or idx >= len(data):
raise ValueError("插件ID不存在...") raise ValueError("插件ID不存在...")
return list(data.keys())[plugin_id] return list(data.keys())[idx]
elif isinstance(plugin_id, str): elif isinstance(plugin_id, str):
if plugin_id not in [v.module for k, v in data.items()]: if plugin_id not in [v.module for k, v in data.items()]:
raise ValueError("插件Module不存在...") raise ValueError("插件Module不存在...")

View File

@ -1,3 +1,4 @@
from nonebot.compat import model_dump
from pydantic import BaseModel from pydantic import BaseModel
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
@ -31,9 +32,12 @@ class StorePluginInfo(BaseModel):
"""插件类型""" """插件类型"""
is_dir: bool is_dir: bool
"""是否为文件夹插件""" """是否为文件夹插件"""
github_url: str | None github_url: str | None = None
"""github链接""" """github链接"""
@property @property
def plugin_type_name(self): def plugin_type_name(self):
return type2name[self.plugin_type.value] return type2name[self.plugin_type.value]
def to_dict(self, **kwargs):
return model_dump(self, **kwargs)

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,9 +42,17 @@ __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,
),
], ],
).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"]
@ -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

@ -27,7 +27,7 @@ __plugin_meta__ = PluginMetadata(
""".strip(), """.strip(),
extra=PluginExtraData( extra=PluginExtraData(
author="HibiKier", version="0.1", plugin_type=PluginType.SUPERUSER author="HibiKier", version="0.1", plugin_type=PluginType.SUPERUSER
).dict(), ).to_dict(),
) )

View File

@ -28,7 +28,7 @@ __plugin_meta__ = PluginMetadata(
default_status=False, default_status=False,
) )
], ],
).dict(), ).to_dict(),
) )
driver = nonebot.get_driver() driver = nonebot.get_driver()

View File

@ -16,8 +16,9 @@ from nonebot_plugin_alconna import (
) )
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.utils import BaseBlock, 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
@ -44,6 +45,14 @@ __plugin_meta__ = PluginMetadata(
version="0.1", version="0.1",
plugin_type=PluginType.NORMAL, plugin_type=PluginType.NORMAL,
menu_type="商店", menu_type="商店",
commands=[
Command(command="我的金币"),
Command(command="我的道具"),
Command(command="购买道具"),
Command(command="使用道具"),
Command(command="金币排行"),
Command(command="金币总排行"),
],
limits=[BaseBlock(check_type=BlockType.GROUP)], limits=[BaseBlock(check_type=BlockType.GROUP)],
configs=[ configs=[
RegisterConfig( RegisterConfig(
@ -53,7 +62,7 @@ __plugin_meta__ = PluginMetadata(
default_value="zhenxun", default_value="zhenxun",
) )
], ],
).dict(), ).to_dict(),
) )
from .goods_register import * # noqa: F403 from .goods_register import * # noqa: F403
@ -194,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

@ -7,9 +7,11 @@ from types import MappingProxyType
from typing import Any, Literal from typing import Any, Literal
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.compat import model_dump
from nonebot_plugin_alconna import UniMessage, UniMsg from nonebot_plugin_alconna import UniMessage, UniMsg
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from pydantic import BaseModel, create_model from pydantic import BaseModel, Field, create_model
from tortoise.expressions import Q
from zhenxun.models.friend_user import FriendUser from zhenxun.models.friend_user import FriendUser
from zhenxun.models.goods_info import GoodsInfo from zhenxun.models.goods_info import GoodsInfo
@ -30,9 +32,9 @@ from .normal_image import normal_image
class Goods(BaseModel): class Goods(BaseModel):
name: str name: str
"""商品名称""" """商品名称"""
before_handle: list[Callable] = [] before_handle: list[Callable] = Field(default_factory=list)
"""使用前函数""" """使用前函数"""
after_handle: list[Callable] = [] after_handle: list[Callable] = Field(default_factory=list)
"""使用后函数""" """使用后函数"""
func: Callable | None = None func: Callable | None = None
"""使用函数""" """使用函数"""
@ -71,6 +73,14 @@ class ShopParam(BaseModel):
"""Uninfo""" """Uninfo"""
message: UniMsg message: UniMsg
"""UniMessage""" """UniMessage"""
extra_data: dict[str, Any] = Field(default_factory=dict)
"""额外数据"""
class Config:
arbitrary_types_allowed = True
def to_dict(self, **kwargs):
return model_dump(self, **kwargs)
async def gold_rank( async def gold_rank(
@ -184,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
@ -193,8 +202,9 @@ class ShopManage:
args: MappingProxyType, args: MappingProxyType,
param: ShopParam, param: ShopParam,
session: Uninfo, session: Uninfo,
message: UniMsg,
**kwargs, **kwargs,
) -> list[Any]: ) -> dict:
"""解析参数 """解析参数
参数: 参数:
@ -202,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.dict() 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,
): ):
@ -240,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(
@ -257,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:
"""运行道具函数 """运行道具函数
@ -270,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(
@ -329,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
@ -366,10 +381,14 @@ class ShopManage:
""" """
if uuid in cls.uuid2goods: if uuid in cls.uuid2goods:
raise ValueError("该商品使用函数已被注册!") raise ValueError("该商品使用函数已被注册!")
kwargs["send_success_msg"] = send_success_msg
kwargs["max_num_limit"] = max_num_limit
cls.uuid2goods[uuid] = Goods( cls.uuid2goods[uuid] = Goods(
model=create_model(f"{uuid}_model", __base__=ShopParam, **kwargs), model=create_model(
f"{uuid}_model",
__base__=ShopParam,
send_success_msg=(bool, Field(default=send_success_msg)),
max_num_limit=(int, Field(default=max_num_limit)),
extra_data=(dict[str, Any], Field(default=kwargs)),
),
params=kwargs, params=kwargs,
before_handle=before_handle, before_handle=before_handle,
after_handle=after_handle, after_handle=after_handle,
@ -392,17 +411,19 @@ class ShopManage:
返回: 返回:
str: 返回小 str: 返回小
""" """
if name == "神秘药水":
return "你们看看就好啦,这是不可能卖给你们的~"
if num < 0: if num < 0:
return "购买的数量要大于0!" return "购买的数量要大于0!"
goods_list = await GoodsInfo.annotate().order_by("id").all() goods_list = (
goods_list = [ await GoodsInfo.filter(
goods Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
for goods in goods_list )
if goods.goods_limit_time > time.time() or goods.goods_limit_time == 0 .annotate()
] .order_by("id")
.all()
)
if name.isdigit(): if name.isdigit():
if int(name) > len(goods_list) or int(name) <= 0:
return "道具编号不存在..."
goods = goods_list[int(name) - 1] goods = goods_list[int(name) - 1]
elif filter_goods := [g for g in goods_list if g.goods_name == name]: elif filter_goods := [g for g in goods_list if g.goods_name == name]:
goods = filter_goods[0] goods = filter_goods[0]
@ -457,24 +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
result = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
data_list = [] user.props = {uuid: count for uuid, count in user.props.items() if count > 0}
uuid2goods = {item.uuid: item for item in result}
column_name = ["-", "使用ID", "名称", "数量", "简介"] goods_list = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
for i, p in enumerate(user.props): goods_by_uuid = {item.uuid: item for item in goods_list}
if prop := uuid2goods.get(p):
data_list.append( table_rows = []
for i, prop_uuid in enumerate(user.props):
prop = goods_by_uuid.get(prop_uuid)
if not prop:
continue
icon = ""
if prop.icon:
icon_path = ICON_PATH / prop.icon
icon = (icon_path, 33, 33) if icon_path.exists() else ""
table_rows.append(
[ [
(ICON_PATH / prop.icon, 33, 33) if prop.icon else "", 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

@ -16,18 +16,3 @@ async def _(user_id: str):
"shop", "shop",
) )
return "使用道具神秘药水成功!你滴金币+1000000" return "使用道具神秘药水成功!你滴金币+1000000"
@shop_register(
name="神秘药水2",
price=999999,
des="鬼知道会有什么效果,要不试试?",
partition="小秘密",
)
async def _(user_id: str):
await UserConsole.add_gold(
user_id,
1000000,
"shop",
)
return "使用道具神秘药水成功!你滴金币+1000000"

View File

@ -1,7 +1,9 @@
from datetime import datetime
import time import time
from nonebot_plugin_htmlrender import template_to_pic from nonebot_plugin_htmlrender import template_to_pic
from pydantic import BaseModel from pydantic import BaseModel
from tortoise.expressions import Q
from zhenxun.configs.config import BotConfig from zhenxun.configs.config import BotConfig
from zhenxun.configs.path_config import TEMPLATE_PATH from zhenxun.configs.path_config import TEMPLATE_PATH
@ -18,35 +20,57 @@ class GoodsItem(BaseModel):
"""分区名称""" """分区名称"""
def get_limit_time(end_time: int):
now = int(time.time())
if now > end_time:
return None
current_datetime = datetime.fromtimestamp(now)
end_datetime = datetime.fromtimestamp(end_time)
time_difference = end_datetime - current_datetime
total_seconds = time_difference.total_seconds()
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
return f"{hours}:{minutes}"
def get_discount(price: int, discount: float):
return None if discount == 1.0 else int(price * discount)
async def html_image() -> bytes: async def html_image() -> bytes:
"""构建图片""" """构建图片"""
goods_list: list[tuple[int, GoodsInfo]] = [ goods_list = (
(i + 1, goods) await GoodsInfo.filter(
for i, goods in enumerate(await GoodsInfo.get_all_goods()) Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time )
] .annotate()
.order_by("id")
.all()
)
partition_dict: dict[str, list[dict]] = {} partition_dict: dict[str, list[dict]] = {}
for goods in goods_list: for idx, goods in enumerate(goods_list):
if not goods[1].partition: if not goods.partition:
goods[1].partition = "默认分区" goods.partition = "默认分区"
if goods[1].partition not in partition_dict: if goods.partition not in partition_dict:
partition_dict[goods[1].partition] = [] partition_dict[goods.partition] = []
icon = None icon = None
if goods[1].icon: if goods.icon:
path = ICON_PATH / goods[1].icon path = ICON_PATH / goods.icon
if path.exists(): if path.exists():
icon = ( icon = (
"data:image/png;base64," "data:image/png;base64,"
f"{BuildImage.open(ICON_PATH / goods[1].icon).pic2bs4()[9:]}" f"{BuildImage.open(ICON_PATH / goods.icon).pic2bs4()[9:]}"
) )
partition_dict[goods[1].partition].append( partition_dict[goods.partition].append(
{ {
"id": goods[0], "id": idx + 1,
"price": goods[1].goods_price, "price": goods.goods_price,
"daily_limit": goods[1].daily_limit or "", "discount_price": get_discount(goods.goods_price, goods.goods_discount),
"name": goods[1].goods_name, "limit_time": get_limit_time(goods.goods_limit_time),
"daily_limit": goods.daily_limit or "",
"name": goods.goods_name,
"icon": icon, "icon": icon,
"description": goods[1].goods_description, "description": goods.goods_description,
} }
) )
data_list = [ data_list = [

View File

@ -1,5 +1,7 @@
import time import time
from tortoise.expressions import Q
from zhenxun.configs.path_config import IMAGE_PATH from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.models.goods_info import GoodsInfo from zhenxun.models.goods_info import GoodsInfo
from zhenxun.utils._build_image import BuildImage from zhenxun.utils._build_image import BuildImage
@ -14,17 +16,19 @@ async def normal_image() -> bytes:
返回: 返回:
BuildImage: 商店图片 BuildImage: 商店图片
""" """
goods_lst = await GoodsInfo.get_all_goods()
h = 10 h = 10
_list: list[GoodsInfo] = [ goods_list = (
goods await GoodsInfo.filter(
for goods in goods_lst Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time )
] .annotate()
.order_by("id")
.all()
)
# A = BuildImage(1100, h, color="#f9f6f2") # A = BuildImage(1100, h, color="#f9f6f2")
total_n = 0 total_n = 0
image_list = [] image_list = []
for idx, goods in enumerate(_list): for idx, goods in enumerate(goods_list):
name_image = BuildImage( name_image = BuildImage(
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf" 580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
) )

View File

@ -12,7 +12,12 @@ from nonebot_plugin_alconna import (
from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_apscheduler import scheduler
from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.utils import PluginCdBlock, PluginExtraData, RegisterConfig from zhenxun.configs.utils import (
Command,
PluginCdBlock,
PluginExtraData,
RegisterConfig,
)
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.depends import UserName from zhenxun.utils.depends import UserName
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
@ -37,6 +42,12 @@ __plugin_meta__ = PluginMetadata(
extra=PluginExtraData( extra=PluginExtraData(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
commands=[
Command(command="签到"),
Command(command="我的签到"),
Command(command="签到排行"),
Command(command="签到总排行"),
],
configs=[ configs=[
RegisterConfig( RegisterConfig(
module="send_setu", module="send_setu",
@ -82,7 +93,7 @@ __plugin_meta__ = PluginMetadata(
), ),
], ],
limits=[PluginCdBlock()], limits=[PluginCdBlock()],
).dict(), ).to_dict(),
) )

View File

@ -16,6 +16,7 @@ from zhenxun.models.sign_log import SignLog
from zhenxun.models.sign_user import SignUser from zhenxun.models.sign_user import SignUser
from zhenxun.utils.http_utils import AsyncHttpx from zhenxun.utils.http_utils import AsyncHttpx
from zhenxun.utils.image_utils import BuildImage from zhenxun.utils.image_utils import BuildImage
from zhenxun.utils.platform import PlatformUtils
from .config import ( from .config import (
SIGN_BACKGROUND_PATH, SIGN_BACKGROUND_PATH,
@ -430,7 +431,9 @@ async def _generate_html_card(
) )
now = datetime.now() now = datetime.now()
data = { data = {
"ava_url": session.user.avatar, "ava_url": PlatformUtils.get_user_avatar_url(
user.user_id, PlatformUtils.get_platform(session), session.self_id
),
"name": nickname, "name": nickname,
"uid": uid, "uid": uid,
"sign_count": f"{user.sign_count}", "sign_count": f"{user.sign_count}",

View File

@ -10,7 +10,7 @@ from nonebot_plugin_alconna import (
) )
from nonebot_plugin_session import EventSession from nonebot_plugin_session import EventSession
from zhenxun.configs.utils import PluginExtraData from zhenxun.configs.utils import Command, PluginExtraData
from zhenxun.utils.enum import PluginType from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
@ -45,7 +45,16 @@ __plugin_meta__ = PluginMetadata(
"全局周功能调用统计", "全局周功能调用统计",
"全局月功能调用统计", "全局月功能调用统计",
""".strip(), """.strip(),
).dict(), commands=[
Command(command="功能调用统计"),
Command(command="日功能调用统计"),
Command(command="周功能调用统计"),
Command(command="我的功能调用统计"),
Command(command="我的日功能调用统计"),
Command(command="我的周功能调用统计"),
Command(command="我的月功能调用统计"),
],
).to_dict(),
) )

View File

@ -20,7 +20,7 @@ __plugin_meta__ = PluginMetadata(
usage="""""".strip(), usage="""""".strip(),
extra=PluginExtraData( extra=PluginExtraData(
author="HibiKier", version="0.1", plugin_type=PluginType.HIDDEN author="HibiKier", version="0.1", plugin_type=PluginType.HIDDEN
).dict(), ).to_dict(),
) )
TEMP_LIST = [] TEMP_LIST = []

View File

@ -32,7 +32,7 @@ __plugin_meta__ = PluginMetadata(
author="", author="",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
from .bot_switch import * # noqa: F403 from .bot_switch import * # noqa: F403

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
@ -38,10 +39,12 @@ __plugin_meta__ = PluginMetadata(
) )
], ],
tasks=[Task(module="broadcast", name="广播")], tasks=[Task(module="broadcast", name="广播")],
).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

@ -26,7 +26,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )

View File

@ -25,7 +25,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
_matcher = on_command( _matcher = on_command(

View File

@ -21,7 +21,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
_friend_matcher = on_alconna( _friend_matcher = on_alconna(
@ -70,8 +70,6 @@ async def _(
msg = f"| UID | 昵称 | 共{len(fl)}个好友\n" + msg msg = f"| UID | 昵称 | 共{len(fl)}个好友\n" + msg
await MessageUtils.build_message(msg).send() await MessageUtils.build_message(msg).send()
logger.info("查看好友列表", "好友列表", session=session) logger.info("查看好友列表", "好友列表", session=session)
except (ApiNotAvailable, AttributeError):
await MessageUtils.build_message("Api未实现...").send()
except Exception as e: except Exception as e:
logger.error("好友列表发生错误", "好友列表", session=session, e=e) logger.error("好友列表发生错误", "好友列表", session=session, e=e)
await MessageUtils.build_message("其他未知错误...").send() await MessageUtils.build_message("其他未知错误...").send()
@ -90,8 +88,6 @@ async def _(
msg = f"| GID | 名称 | 共{len(gl)}个群组\n" + msg msg = f"| GID | 名称 | 共{len(gl)}个群组\n" + msg
await MessageUtils.build_message(msg).send() await MessageUtils.build_message(msg).send()
logger.info("查看群组列表", "群组列表", session=session) logger.info("查看群组列表", "群组列表", session=session)
except (ApiNotAvailable, AttributeError):
await MessageUtils.build_message("Api未实现...").send()
except Exception as e: except Exception as e:
logger.error("查看群组列表发生错误", "群组列表", session=session, e=e) logger.error("查看群组列表发生错误", "群组列表", session=session, e=e)
await MessageUtils.build_message("其他未知错误...").send() await MessageUtils.build_message("其他未知错误...").send()

View File

@ -53,7 +53,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )

View File

@ -37,7 +37,7 @@ __plugin_meta__ = PluginMetadata(
type=int, type=int,
), ),
], ],
).dict(), ).to_dict(),
) )
_matcher = on_alconna( _matcher = on_alconna(

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
@ -46,7 +47,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )
@ -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

@ -36,7 +36,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )

View File

@ -32,7 +32,7 @@ __plugin_meta__ = PluginMetadata(
default_value="zhenxun", default_value="zhenxun",
) )
], ],
).dict(), ).to_dict(),
) )
_matcher = on_alconna( _matcher = on_alconna(

View File

@ -15,7 +15,8 @@ async def get_task() -> dict[str, str] | None:
return { return {
"name": "被动技能", "name": "被动技能",
"description": "控制群组中的被动技能状态", "description": "控制群组中的被动技能状态",
"usage": "通过 开启/关闭群被动 来控制群被动 <br> ---------- <br> " "usage": "通过 开启/关闭群被动 来控制群被动 <br>"
+ " 示例:开启/关闭群被动早晚安 <br> ---------- <br> "
+ "<br>".join([task.name for task in task_list]), + "<br>".join([task.name for task in task_list]),
} }
return None return None

View File

@ -0,0 +1,114 @@
from decimal import Decimal
from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata
from nonebot_plugin_alconna import Alconna, Args, Arparma, At, Field, on_alconna
from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.sign_user import SignUser
from zhenxun.models.user_console import UserConsole
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
from zhenxun.utils.platform import PlatformUtils
__plugin_meta__ = PluginMetadata(
name="高贵的作弊器",
description="这是一个作弊器,设置用户金币数量和好感度",
usage="""
金币设置 100金币数量 @用户
好感度设置 100好感度 @用户
""".strip(),
extra=PluginExtraData(
author="HibiKier",
version="0.1",
plugin_type=PluginType.SUPERUSER,
).to_dict(),
)
_gold_matcher = on_alconna(
Alconna(
"金币设置",
Args[
"gold",
int,
Field(
missing_tips=lambda: "请在命令后跟随金币数量!",
unmatch_tips=lambda _: "金币数量必须为数字!",
),
][
"at_user",
At,
Field(
missing_tips=lambda: "必须要at一名指定用户",
),
],
),
skip_for_unmatch=False,
permission=SUPERUSER,
priority=5,
block=True,
)
_impression_matcher = on_alconna(
Alconna(
"好感度设置",
Args[
"impression",
float,
Field(
missing_tips=lambda: "请在命令后跟随好感度!",
unmatch_tips=lambda _: "好感度数量必须为数字!",
),
][
"at_user",
At,
Field(
missing_tips=lambda: "必须要at一名指定用户",
),
],
),
skip_for_unmatch=False,
permission=SUPERUSER,
priority=5,
block=True,
)
@_gold_matcher.handle()
async def _(session: Uninfo, arparma: Arparma, gold: int, at_user: At):
user = await UserConsole.get_user(
at_user.target, PlatformUtils.get_platform(session)
)
user.gold = gold
await user.save(update_fields=["gold"])
await MessageUtils.build_message(
["成功将用户", at_user, f"的金币设置为 {gold}"]
).send(reply_to=True)
logger.info(
f"成功将用户{at_user.target}的金币设置为{gold}",
arparma.header_result,
session=session,
)
@_impression_matcher.handle()
async def _(session: Uninfo, arparma: Arparma, impression: float, at_user: At):
platform = PlatformUtils.get_platform(session)
user_console = await UserConsole.get_user(at_user.target, platform)
user, _ = await SignUser.get_or_create(
user_id=at_user.target,
defaults={"user_console": user_console, "platform": platform},
)
user.impression = Decimal(impression)
await user.save(update_fields=["impression"])
await MessageUtils.build_message(
["成功将用户", at_user, f"的好感度设置为 {impression}"]
).send(reply_to=True)
logger.info(
f"成功将用户{at_user.target}的好感度设置为{impression}",
arparma.header_result,
session=session,
)

View File

@ -22,7 +22,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier", author="HibiKier",
version="0.1", version="0.1",
plugin_type=PluginType.SUPERUSER, plugin_type=PluginType.SUPERUSER,
).dict(), ).to_dict(),
) )

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