更改冲突

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=["真寻", "小真寻", "绪山真寻", "小寻子"]
SESSION_EXPIRE_TIMEOUT=30
SESSION_EXPIRE_TIMEOUT=00:00:30
ALCONNA_USE_COMMAND_START=True

View File

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

View File

@ -1,7 +1,7 @@
name: 功能建议
title: "Feature: 功能描述"
description: 提出关于项目新功能的想法
labels: ["enhancement"]
labels: [ "enhancement" ]
body:
- type: textarea
id: problem
@ -18,3 +18,10 @@ body:
description: 请说明需要的功能或解决方法
validations:
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": [
"charliermarsh.ruff",
"esbenp.prettier-vscode",
"ms-python.black-formatter",
"ms-python.isort",
"ms-python.python",
"ms-python.vscode-pylance"
]

View File

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

View File

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

8
bot.py
View File

@ -1,8 +1,8 @@
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.dodo import Adapter as DoDoAdapter
# from nonebot.adapters.kaiheila import Adapter as KaiheilaAdapter
from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter
nonebot.init()
@ -10,8 +10,8 @@ nonebot.init()
driver = nonebot.get_driver()
driver.register_adapter(OneBotV11Adapter)
driver.register_adapter(KaiheilaAdapter)
driver.register_adapter(DoDoAdapter)
# driver.register_adapter(KaiheilaAdapter)
# driver.register_adapter(DoDoAdapter)
# driver.register_adapter(DiscordAdapter)
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"
playwright = "^1.41.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" }
cattrs = "^23.2.3"
ruamel-yaml = "^0.18.5"
strenum = "^0.4.15"
nonebot-plugin-session = "^0.2.3"
ujson = "^5.9.0"
nonebot-adapter-kaiheila = "^0.3.0"
nb-cli = "^1.3.0"
nonebot2 = "^2.1.3"
pydantic = "1.10.18"
nonebot-adapter-discord = "^0.1.3"
nonebot-adapter-dodo = "^0.1.4"
nonebot2 = { extras = ["fastapi"], version = "^2.3.3" }
pillow = "^10.0.0"
retrying = "^1.3.4"
aiofiles = "^23.2.1"
nonebot-plugin-htmlrender = "^0.3.0"
nonebot-plugin-userinfo = "^0.1.3"
nonebot-plugin-htmlrender = ">=0.6.0,<1.0.0"
pypinyin = "^0.51.0"
beautifulsoup4 = "^4.12.3"
lxml = "^5.1.0"
@ -46,14 +41,17 @@ python-jose = { extras = ["cryptography"], version = "^3.3.0" }
python-multipart = "^0.0.9"
aiocache = "^0.12.2"
py-cpuinfo = "^9.0.0"
nonebot-plugin-uninfo = "^0.4.1"
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"
pytest-cov = "^5.0.0"
pytest-mock = "^3.6.1"
pytest-asyncio = "^0.23.5"
pytest-asyncio = "^0.25"
pytest-xdist = "^3.3.1"
respx = "^0.21.1"
ruff = "^0.8.0"
@ -65,14 +63,13 @@ plugins = [
"nonebot_plugin_apscheduler",
"nonebot_plugin_session",
"nonebot_plugin_htmlrender",
"nonebot_plugin_userinfo",
"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" },
# { name = "DoDo", module_name = "nonebot.adapters.dodo" },
# { name = "开黑啦", module_name = "nonebot.adapters.kaiheila" },
]
[tool.ruff]
@ -84,24 +81,24 @@ line-ending = "lf"
[tool.ruff.lint]
select = [
"F", # Pyflakes
"W", # pycodestyle warnings
"E", # pycodestyle errors
"I", # isort
"UP", # pyupgrade
"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
"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
"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

View File

@ -1,50 +1,49 @@
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"
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"
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"
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"
attrs==24.2.0 ; python_version >= "3.10" and python_version < "4.0"
beautifulsoup4==4.12.3 ; python_version >= "3.10" and python_version < "4.0"
attrs==25.1.0 ; 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"
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"
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"
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"
click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
cn2an==0.5.22 ; 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.8 ; 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")
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"
dateparser==1.2.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.1 ; 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"
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"
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"
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"
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"
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"
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"
imagehash==4.3.1 ; python_version >= "3.10" and python_version < "4.0"
importlib-metadata==8.5.0 ; 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.6.1 ; 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"
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==3.7 ; 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"
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"
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-plugin-alconna==0.54.1 ; 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-htmlrender==0.3.5 ; 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.5.0 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-htmlrender==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-session==0.2.3 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-uninfo==0.4.1 ; 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.0 ; 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.0 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-uninfo==0.6.8 ; python_version >= "3.10" and python_version < "4.0"
nonebot-plugin-waiter==0.8.1 ; python_version >= "3.10" and python_version < "4.0"
nonebot2==2.4.1 ; python_version >= "3.10" and python_version < "4.0"
nonebot2[fastapi]==2.4.1 ; python_version >= "3.10" and python_version < "4.0"
noneprompt==0.1.9 ; python_version >= "3.10" and python_version < "4.0"
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"
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"
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"
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"
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"
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"
pyee==12.0.0 ; python_version >= "3.10" and python_version < "4.0"
pydantic-core==2.27.2 ; python_version >= "3.10" and python_version < "4.0"
pydantic==2.10.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"
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"
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"
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"
@ -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-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"
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"
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"
@ -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"
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==0.18.6 ; python_version >= "3.10" and python_version < "4.0"
scipy==1.14.1 ; python_version >= "3.10" and python_version < "4.0"
setuptools==75.6.0 ; python_version >= "3.10" and python_version < "4.0"
ruamel-yaml==0.18.10 ; python_version >= "3.10" and python_version < "4.0"
scipy==1.15.1 ; 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"
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"
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"
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"
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"
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"
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"
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"
uvicorn[standard]==0.32.1 ; 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"
urllib3==2.3.0 ; 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"
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"
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"
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"

View File

@ -3,10 +3,6 @@ import os
import re
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.log import logger
@ -17,8 +13,6 @@ from zhenxun.services.db_context import disconnect, init
driver = nonebot.get_driver()
driver.register_adapter(OneBotV11Adapter)
driver.register_adapter(KaiheilaAdapter)
driver.register_adapter(DoDoAdapter)
driver.on_startup(init)

View File

@ -1,3 +1,4 @@
from collections import namedtuple
from collections.abc import Callable
from pathlib import Path
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):
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.get_cpu_info.return_value = cpuinfo_get_cpu_info
@ -95,28 +130,35 @@ async def test_check(
)
ctx.receive_event(bot=bot, event=event)
ctx.should_ignore_rule(_self_check_matcher)
data = {
"cpu_info": f"{mock_psutil.cpu_percent.return_value}% "
+ f"- {mock_psutil.cpu_freq.return_value.current}Ghz "
+ f"[{mock_psutil.cpu_count.return_value} core]",
"cpu_process": mock_psutil.cpu_percent.return_value,
"ram_info": f"{round(mock_psutil.virtual_memory.return_value.used / (1024 ** 3), 1)}" # noqa: E501
+ f" / {round(mock_psutil.virtual_memory.return_value.total / (1024 ** 3), 1)}"
+ " GB",
"ram_process": mock_psutil.virtual_memory.return_value.percent,
"swap_info": f"{round(mock_psutil.swap_memory.return_value.used / (1024 ** 3), 1)}" # noqa: E501
+ f" / {round(mock_psutil.swap_memory.return_value.total / (1024 ** 3), 1)} GB",
"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"],
"baidu": "red",
"google": "red",
"system": f"{platform_uname.system} " f"{platform_uname.release}",
"version": __get_version(),
"plugin_count": len(nonebot.get_loaded_plugins()),
"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": {
"cpu_info": "1.0% - 1.0Ghz [1 core]",
"cpu_process": 1.0,
"ram_info": "1.0 / 1.0 GB",
"ram_process": 100.0,
"swap_info": "1.0 / 1.0 GB",
"swap_process": 100.0,
"disk_info": "1.0 / 1.0 GB",
"disk_process": 100.0,
"brand_raw": cpuinfo_get_cpu_info["brand_raw"],
"baidu": "red",
"google": "red",
"system": f"{platform_uname.system} " f"{platform_uname.release}",
"version": __get_version(),
"plugin_count": len(nonebot.get_loaded_plugins()),
"nickname": BotConfig.self_nickname,
}
},
templates={"data": data},
pages={
"viewport": {"width": 195, "height": 750},
"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("is_commit", [True, False])
async def test_add_plugin_basic(
package_api: str,
is_commit: bool,
app: App,
mocker: MockerFixture,
mocked_api: MockRouter,
@ -40,6 +42,12 @@ async def test_add_plugin_basic(
if package_api != "gh":
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
async with app.test_matcher(_matcher) as ctx:
@ -67,15 +75,22 @@ async def test_add_plugin_basic(
result=None,
bot=bot,
)
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
assert mocked_api["search_image_plugin_file_init"].called
if is_commit:
assert mocked_api["search_image_plugin_file_init_commit"].called
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
else:
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()
@pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_basic_commit_version(
package_api: str,
is_commit: bool,
app: App,
mocker: MockerFixture,
mocked_api: MockRouter,
@ -98,6 +113,11 @@ async def test_add_plugin_basic_commit_version(
if package_api != "gh":
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
async with app.test_matcher(_matcher) as ctx:
@ -125,19 +145,25 @@ async def test_add_plugin_basic_commit_version(
result=None,
bot=bot,
)
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
if package_api == "jsd":
assert mocked_api["zhenxun_bot_plugins_metadata_commit"].called
if package_api == "gh":
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 (mock_base_path / "plugins" / "bilibili_sub" / "__init__.py").is_file()
@pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_basic_is_not_dir(
package_api: str,
is_commit: bool,
app: App,
mocker: MockerFixture,
mocked_api: MockRouter,
@ -160,6 +186,12 @@ async def test_add_plugin_basic_is_not_dir(
if package_api != "gh":
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
async with app.test_matcher(_matcher) as ctx:
@ -187,15 +219,22 @@ async def test_add_plugin_basic_is_not_dir(
result=None,
bot=bot,
)
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
assert mocked_api["jitang_plugin_file"].called
if is_commit:
assert mocked_api["jitang_plugin_file_commit"].called
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
else:
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()
@pytest.mark.parametrize("package_api", ["jsd", "gh"])
@pytest.mark.parametrize("is_commit", [True, False])
async def test_add_plugin_extra(
package_api: str,
is_commit: bool,
app: App,
mocker: MockerFixture,
mocked_api: MockRouter,
@ -218,6 +257,14 @@ async def test_add_plugin_extra(
if package_api != "gh":
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
async with app.test_matcher(_matcher) as ctx:
@ -245,9 +292,14 @@ async def test_add_plugin_extra(
result=None,
bot=bot,
)
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
assert mocked_api["github_sub_plugin_file_init"].called
if is_commit:
assert mocked_api["github_sub_plugin_file_init_commit"].called
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
else:
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()

View File

@ -112,7 +112,7 @@ async def test_plugin_store_fail(
init_mocked_api(mocked_api=mocked_api)
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",
).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["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()

View File

@ -65,7 +65,7 @@ async def test_update_plugin_basic_need_update(
)
assert mocked_api["basic_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()

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",
name="zhenxun_bot_plugins_metadata_commit",
).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
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",
name="zhenxun_bot_plugins_tree_commit",
).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(
"https://raw.githubusercontent.com/",
@ -51,36 +59,89 @@ def init_mocked_api(mocked_api: MockRouter) -> None:
).respond(200, text="")
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",
).respond(json=get_response_json("basic_plugins.json"))
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",
).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(
"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",
).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",
"https://cdn.jsdelivr.net/gh/zhenxun-org/zhenxun_bot_plugins_index@2ed61284873c526802752b12a3fd3b5e1a59d948/plugins.json",
name="extra_plugins_jsdelivr",
).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(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/search_image/__init__.py",
name="search_image_plugin_file_init",
).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(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/main/plugins/alapi/jitang.py",
name="jitang_plugin_file",
).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(
"https://raw.githubusercontent.com/xuanerwa/zhenxun_github_sub/main/github_sub/__init__.py",
name="github_sub_plugin_file_init",
).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(
"https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot_plugins/b101fbc/plugins/bilibili_sub/__init__.py",
name="bilibili_sub_plugin_file_init",
).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 respx import MockRouter
from tests.config import BotId, UserId
from tests.config import BotId, GroupId, UserId
nonebot.load_plugin("nonebot_plugin_session")
@ -47,7 +47,7 @@ def pytest_configure(config: pytest.Config) -> None:
},
"host": "127.0.0.1",
"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_apscheduler")
nonebot.load_plugin("nonebot_plugin_userinfo")
nonebot.load_plugin("nonebot_plugin_htmlrender")
nonebot.load_plugins("zhenxun/builtin_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
async def app(app: App, tmp_path: Path, mocker: MockerFixture):

View File

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

View File

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

View File

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

View File

@ -14,5 +14,5 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier",
version="0.1",
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(),
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",
)
],
).dict(),
).to_dict(),
)
_matcher = on_alconna(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -80,7 +80,7 @@ __plugin_meta__ = PluginMetadata(
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.models.group_console import GroupConsole
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):
"""删除帮助图片"""
if gid:
file = GROUP_HELP_PATH / f"{gid}.png"
if file.exists():
file.unlink()
for file in os.listdir(GROUP_HELP_PATH):
if file.startswith(f"{gid}"):
os.remove(GROUP_HELP_PATH / file)
else:
if HELP_FILE.exists():
HELP_FILE.unlink()

View File

@ -57,7 +57,7 @@ __plugin_meta__ = PluginMetadata(
default_value=2,
)
],
).dict(),
).to_dict(),
)
_matcher = on_command(
@ -125,7 +125,7 @@ async def _(session: Uninfo, arparma: Arparma, idx: Match[int]):
@_del_matcher.handle()
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:
await MessageUtils.build_message("未查找到指定id的群组欢迎消息...").finish()
await MessageUtils.build_message(result).send()

View File

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

View File

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

View File

@ -29,7 +29,7 @@ __plugin_meta__ = PluginMetadata(
type=bool,
)
],
).dict(),
).to_dict(),
)
@ -39,7 +39,6 @@ def rule(message: UniMsg) -> bool:
chat_history = on_message(rule=rule, priority=1, block=False)
TEMP_LIST = []
@ -70,14 +69,4 @@ async def _():
await ChatHistory.bulk_create(message_list)
logger.debug(f"批量添加聊天记录 {len(message_list)}", "定时任务")
except Exception as e:
logger.error("定时批量添加聊天记录", "定时任务", 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))
logger.warning("存储聊天记录失败", "chat_history", e=e)

View File

@ -14,7 +14,7 @@ from nonebot_plugin_alconna import (
from nonebot_plugin_session import EventSession
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.group_member_info import GroupInfoUser
from zhenxun.services.log import logger
@ -45,7 +45,14 @@ __plugin_meta__ = PluginMetadata(
version="0.1",
plugin_type=PluginType.NORMAL,
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",
)
],
).dict(),
).to_dict(),
)

View File

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

View File

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

View File

@ -1,3 +1,5 @@
from pathlib import Path
import nonebot
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.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 .normal_help import build_normal_image
from .zhenxun_help import build_zhenxun_image
@ -20,7 +27,9 @@ background = IMAGE_PATH / "background" / "0.png"
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:
case "html":
result = BuildImage.open(await build_html_image(group_id))
result = BuildImage.open(await build_html_image(group_id, is_detail))
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 _:
result = await build_normal_image(group_id)
save_path = GROUP_HELP_PATH / f"{group_id}.png" if group_id else SIMPLE_HELP_IMAGE
result = await build_normal_image(group_id, is_detail)
if group_id:
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)
return save_path
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
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
is_detail: 是否详细帮助
返回:
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:
if not classify.get(menu):
classify[menu] = []
classify[menu].append(handle(plugin, group))
classify[menu].append(handle(plugin, group, is_detail))
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
参数:
plugin: PluginInfo
group: 群组
is_detail: 是否详细
返回:
Item: Item
@ -116,13 +119,14 @@ def build_plugin_data(classify: dict[str, list[Item]]) -> list[dict[str, str]]:
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帮助图片
参数:
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)
return await template_to_pic(
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"
async def build_normal_image(group_id: str | None) -> BuildImage:
async def build_normal_image(group_id: str | None, is_detail: bool) -> BuildImage:
"""构造PIL帮助图片
参数:
group_id: 群号
is_detail: 详细帮助
"""
image_list = []
font_size = 24

View File

@ -1,9 +1,11 @@
import nonebot
from nonebot_plugin_htmlrender import template_to_pic
from nonebot_plugin_uninfo import Uninfo
from pydantic import BaseModel
from zhenxun.configs.config import BotConfig
from zhenxun.configs.path_config import TEMPLATE_PATH
from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.group_console import GroupConsole
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.utils.enum import BlockType
@ -15,9 +17,11 @@ from ._utils import classify_plugin
class Item(BaseModel):
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
参数:
@ -36,7 +40,12 @@ def __handle_item(plugin: PluginInfo, group: GroupConsole | None):
plugin.name = f"{plugin.name}(不可用)"
elif group and f"{plugin.module}," in group.block_plugin:
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]]:
@ -123,18 +132,24 @@ def build_line_data(plugin_list: list[dict]) -> list[dict]:
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
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)
platform = PlatformUtils.get_platform(session)
bot_id = BotConfig.get_qbot_uid(session.self_id) or session.self_id
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(
template_path=str((TEMPLATE_PATH / "ss_menu").absolute()),
template_name="main.html",
@ -142,10 +157,13 @@ async def build_zhenxun_image(session: Uninfo, group_id: str | None) -> bytes:
"data": {
"plugin_list": plugin_list,
"ava": bot_ava,
"width": width,
"font_size": (title_font, tip_font),
"is_detail": is_detail,
}
},
pages={
"viewport": {"width": 637, "height": 453},
"viewport": {"width": width, "height": 453},
"base_url": f"file://{TEMPLATE_PATH}",
},
wait=2,

View File

@ -2,11 +2,12 @@ import os
import random
from nonebot import on_message
from nonebot.adapters import Event
from nonebot.matcher import Matcher
from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import UniMsg
from nonebot_plugin_session import EventSession
from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.configs.utils import PluginExtraData
@ -26,10 +27,25 @@ __plugin_meta__ = PluginMetadata(
version="0.1",
plugin_type=PluginType.DEPENDANT,
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"
@ -37,33 +53,30 @@ _path = IMAGE_PATH / "_base" / "laugh"
@_matcher.handle()
async def _(matcher: Matcher, message: UniMsg, session: EventSession):
gid = session.id3 or session.id2
if await BanConsole.is_ban(session.id1, gid):
text = message.extract_plain_text().strip()
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
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
if _path.exists():
if files := os.listdir(_path):
image = _path / random.choice(files)
message_list = []
if image:
message_list.append(image)
message_list.append(
"桀桀桀,预判到会有 '笨蛋' 把功能名称当命令用,特地前来嘲笑!"
f"但还是好心来帮帮你啦!\n请at我发送 '帮助{plugin.name}' 或者"
f" '帮助{plugin.id}' 来获取该功能帮助!"
)
logger.info(
"检测到功能名称当命令使用,已发送帮助信息", "功能帮助", session=session
)
await MessageUtils.build_message(message_list).send(reply_to=True)
matcher.stop_propagation()
image = None
if _path.exists():
if files := os.listdir(_path):
image = _path / random.choice(files)
message_list = []
if image:
message_list.append(image)
message_list.append(
"桀桀桀,预判到会有 '笨蛋' 把功能名称当命令用,特地前来嘲笑!"
f"但还是好心来帮帮你啦!\n请at我发送 '帮助{plugin.name}' 或者"
f" '帮助{plugin.id}' 来获取该功能帮助!"
)
logger.info("检测到功能名称当命令使用,已发送帮助信息", "功能帮助", session=session)
await MessageUtils.build_message(message_list).send(reply_to=True)
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 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.services.log import logger
from zhenxun.utils.depends import UserName
@ -20,7 +20,9 @@ __plugin_meta__ = PluginMetadata(
指令
我的信息 ?[at]
""".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: 图片数据
"""
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)
level = await LevelUser.get_user_level(user_id, group_id)
sign_level = 0

View File

@ -49,7 +49,7 @@ def _handle_config(plugin: Plugin, exists_module: list[str]):
arg_parser=reg_config.arg_parser,
_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]):
@ -62,6 +62,7 @@ def _generate_simple_config(exists_module: list[str]):
# 读取用户配置
_data = {}
_tmp_data = {}
exists_module += Config.add_module
if SIMPLE_CONFIG_FILE.exists():
_data = _yaml.load(SIMPLE_CONFIG_FILE.open(encoding="utf8"))
# 将简易配置文件的数据填充到配置文件
@ -71,7 +72,7 @@ def _generate_simple_config(exists_module: list[str]):
try:
if _data.get(module) and k in _data[module].keys():
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)
except AttributeError as 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,
plugin_type=extra_data.plugin_type,
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),
impression=setting.impression,
)
)
if extra_data.limits:

View File

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

View File

@ -16,7 +16,9 @@ except ImportError:
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()))
except ImportError:

View File

@ -84,7 +84,7 @@ __plugin_meta__ = PluginMetadata(
default_status=False,
),
],
).dict(),
).to_dict(),
)
@ -116,19 +116,19 @@ async def _(
session: Uninfo,
event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent,
):
user_id = str(event.user_id)
group_id = str(event.group_id)
if user_id == bot.self_id:
if session.user.id == bot.self_id:
"""新成员为bot本身"""
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:
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:
await PlatformUtils.send_superuser(bot, e.get_info())
else:
await GroupManager.add_user(session, bot, user_id, group_id)
await GroupManager.add_user(session, bot)
@group_decrease_handle.handle()

View File

@ -4,6 +4,7 @@ from pathlib import Path
import random
from nonebot.adapters import Bot
from nonebot.exception import ActionFailed
from nonebot_plugin_alconna import At, UniMessage
from nonebot_plugin_uninfo import Uninfo
import ujson as json
@ -217,33 +218,45 @@ class GroupManager:
msg_list.insert(0, At("user", user_id))
logger.info("发送群欢迎消息...", "入群检测", session=session)
if msg_list:
await MessageUtils.build_message(msg_list).send() # type: ignore
else:
image = DEFAULT_IMAGE_PATH / random.choice(
os.listdir(DEFAULT_IMAGE_PATH)
)
await MessageUtils.build_message(
[
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
image,
]
).send()
await MessageUtils.build_message(msg_list).finish() # type: ignore
image = DEFAULT_IMAGE_PATH / random.choice(os.listdir(DEFAULT_IMAGE_PATH))
await MessageUtils.build_message(
[
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
image,
]
).send()
@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
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()
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(
user_id=str(user_info["user_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']} 更新成功")
if not await CommonUtils.task_is_block(
@ -312,10 +325,13 @@ class GroupManager:
group_id=group_id,
)
if sub_type == "kick":
operator = await bot.get_group_member_info(
user_id=int(operator_id), group_id=int(group_id)
)
operator_name = operator["card"] or operator["nickname"]
if operator_id != "0":
operator = await bot.get_group_member_info(
user_id=int(operator_id), group_id=int(group_id)
)
operator_name = operator["card"] or operator["nickname"]
else:
operator_name = ""
return f"{user_name}{operator_name} 送走了."
elif sub_type == "leave":
return f"{user_name}离开了我们..."

View File

@ -7,6 +7,7 @@ from zhenxun.configs.utils import PluginExtraData
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
from zhenxun.utils.utils import is_number
from .data_source import ShopManage
@ -25,16 +26,16 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier",
version="0.1",
plugin_type=PluginType.SUPERUSER,
).dict(),
).to_dict(),
)
_matcher = on_alconna(
Alconna(
"插件商店",
Subcommand("add", Args["plugin_id", int | str]),
Subcommand("remove", Args["plugin_id", int | str]),
Subcommand("add", Args["plugin_id", str]),
Subcommand("remove", Args["plugin_id", 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"),
),
permission=SUPERUSER,
@ -43,14 +44,14 @@ _matcher = on_alconna(
)
_matcher.shortcut(
r"添加插件",
r"(添加|安装)插件",
command="插件商店",
arguments=["add", "{%0}"],
prefix=True,
)
_matcher.shortcut(
r"移除插件",
r"(移除|卸载)插件",
command="插件商店",
arguments=["remove", "{%0}"],
prefix=True,
@ -90,12 +91,12 @@ async def _(session: EventSession):
@_matcher.assign("add")
async def _(session: EventSession, plugin_id: int | str):
async def _(session: EventSession, plugin_id: str):
try:
if isinstance(plugin_id, str):
await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send()
else:
if is_number(plugin_id):
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)
except Exception as 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")
async def _(session: EventSession, plugin_id: int | str):
async def _(session: EventSession, plugin_id: str):
try:
result = await ShopManage.remove_plugin(plugin_id)
except Exception as e:
@ -138,12 +139,12 @@ async def _(session: EventSession, plugin_name_or_author: str):
@_matcher.assign("update")
async def _(session: EventSession, plugin_id: int | str):
async def _(session: EventSession, plugin_id: str):
try:
if isinstance(plugin_id, str):
await MessageUtils.build_message(f"正在更新插件 Module: {plugin_id}").send()
else:
if is_number(plugin_id):
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)
except Exception as 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.http_utils import AsyncHttpx
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
@ -50,7 +51,7 @@ def install_requirement(plugin_path: Path):
try:
result = subprocess.run(
["pip", "install", "-r", str(existing_requirements)],
["poetry", "run", "pip", "install", "-r", str(existing_requirements)],
check=True,
capture_output=True,
text=True,
@ -79,12 +80,17 @@ class ShopManage:
返回:
dict: 插件信息数据
"""
default_github_url = await GithubUtils.parse_github_url(
DEFAULT_GITHUB_URL
).get_raw_download_urls("plugins.json")
extra_github_url = await GithubUtils.parse_github_url(
EXTRA_GITHUB_URL
).get_raw_download_urls("plugins.json")
default_github_repo = GithubUtils.parse_github_url(DEFAULT_GITHUB_URL)
extra_github_repo = GithubUtils.parse_github_url(EXTRA_GITHUB_URL)
for repo_info in [default_github_repo, extra_github_repo]:
if await repo_info.update_repo_commit():
logger.info(f"获取最新提交: {repo_info.branch}", "插件管理")
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)
res2 = await AsyncHttpx.get(extra_github_url)
@ -175,7 +181,7 @@ class ShopManage:
)
@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]
repo_api: RepoAPI
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}", "插件管理")
for repo_api in GithubUtils.iter_api_strategies():
try:
@ -231,8 +241,9 @@ class ShopManage:
raise ValueError("所有API获取插件文件失败请检查网络连接")
if module_path == ".":
module_path = ""
replace_module_path = module_path.replace(".", "/")
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,
)
download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
@ -247,28 +258,35 @@ class ShopManage:
else:
# 安装依赖
plugin_path = base_path / "/".join(module_path.split("."))
req_files = repo_api.get_files(REQ_TXT_FILE_STRING, False)
req_files.extend(repo_api.get_files("requirement.txt", False))
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
req_download_urls = [
await repo_info.get_raw_download_urls(file) for file in req_files
]
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
if req_files:
result = await AsyncHttpx.gather_download_file(
req_download_urls, req_paths
try:
req_files = repo_api.get_files(
f"{replace_module_path}/{REQ_TXT_FILE_STRING}", False
)
for success in result:
if not success:
raise Exception("插件依赖文件下载失败")
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
install_requirement(plugin_path)
req_files.extend(
repo_api.get_files(f"{replace_module_path}/requirement.txt", False)
)
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
req_download_urls = [
await repo_info.get_raw_download_urls(file) for file in req_files
]
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
if req_files:
result = await AsyncHttpx.gather_download_file(
req_download_urls, req_paths
)
for success in result:
if not success:
raise Exception("插件依赖文件下载失败")
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
install_requirement(plugin_path)
except ValueError as e:
logger.warning("未获取到依赖文件路径...", e=e)
return True
raise Exception("插件下载失败")
raise Exception("插件下载失败...")
@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
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
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()
if isinstance(plugin_id, int):
if plugin_id < 0 or plugin_id >= len(data):
if is_number(plugin_id):
idx = int(plugin_id)
if idx < 0 or idx >= len(data):
raise ValueError("插件ID不存在...")
return list(data.keys())[plugin_id]
return list(data.keys())[idx]
elif isinstance(plugin_id, str):
if plugin_id not in [v.module for k, v in data.items()]:
raise ValueError("插件Module不存在...")

View File

@ -1,3 +1,4 @@
from nonebot.compat import model_dump
from pydantic import BaseModel
from zhenxun.utils.enum import PluginType
@ -31,9 +32,12 @@ class StorePluginInfo(BaseModel):
"""插件类型"""
is_dir: bool
"""是否为文件夹插件"""
github_url: str | None
github_url: str | None = None
"""github链接"""
@property
def plugin_type_name(self):
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
import random
import time
from nonebot import on_message, on_request
@ -40,9 +42,17 @@ __plugin_meta__ = PluginMetadata(
help="是否自动同意好友添加",
type=bool,
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,
)
await asyncio.sleep(random.randint(1, 10))
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.create(
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):
if event.sub_type != "invite":
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:
logger.debug(
"超级用户自动同意加入群聊",
"超级用户自动同意加入群聊或开启自动同意入群",
"群聊请求",
session=event.user_id,
target=event.group_id,
@ -154,12 +165,42 @@ async def _(bot: v12Bot | v11Bot, event: GroupRequestEvent, session: EventSessio
)
except ActionFailed as e:
logger.error(
"级用户自动同意加入群聊发生错误",
"级用户自动同意加入群聊或开启自动同意入群,加入群组发生错误",
"群聊请求",
session=event.user_id,
target=event.group_id,
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}"):
logger.debug(
f"收录 用户[{event.user_id}] 群聊[{event.group_id}] 群聊请求",

View File

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

View File

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

View File

@ -16,8 +16,9 @@ from nonebot_plugin_alconna import (
)
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.utils.decorator.shop import NotMeetUseConditionsException
from zhenxun.utils.depends import UserName
from zhenxun.utils.enum import BlockType, PluginType
from zhenxun.utils.exception import GoodsNotFound
@ -44,6 +45,14 @@ __plugin_meta__ = PluginMetadata(
version="0.1",
plugin_type=PluginType.NORMAL,
menu_type="商店",
commands=[
Command(command="我的金币"),
Command(command="我的道具"),
Command(command="购买道具"),
Command(command="使用道具"),
Command(command="金币排行"),
Command(command="金币总排行"),
],
limits=[BaseBlock(check_type=BlockType.GROUP)],
configs=[
RegisterConfig(
@ -53,7 +62,7 @@ __plugin_meta__ = PluginMetadata(
default_value="zhenxun",
)
],
).dict(),
).to_dict(),
)
from .goods_register import * # noqa: F403
@ -194,6 +203,12 @@ async def _(
await MessageUtils.build_message(
f"没有找到道具 {name.result} 或道具数量不足..."
).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")

View File

@ -7,9 +7,11 @@ from types import MappingProxyType
from typing import Any, Literal
from nonebot.adapters import Bot, Event
from nonebot.compat import model_dump
from nonebot_plugin_alconna import UniMessage, UniMsg
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.goods_info import GoodsInfo
@ -30,9 +32,9 @@ from .normal_image import normal_image
class Goods(BaseModel):
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
"""使用函数"""
@ -71,6 +73,14 @@ class ShopParam(BaseModel):
"""Uninfo"""
message: UniMsg
"""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(
@ -111,7 +121,7 @@ async def gold_rank(
)
data_list.append(
[
f"{i+1}",
f"{i + 1}",
(ava_bytes, 30, 30) if platform == "qq" else "",
uid2name.get(user[0]),
user[1],
@ -184,7 +194,6 @@ class ShopManage:
"num": num,
"text": text,
"goods_name": goods.name,
"message": message,
}
@classmethod
@ -193,8 +202,9 @@ class ShopManage:
args: MappingProxyType,
param: ShopParam,
session: Uninfo,
message: UniMsg,
**kwargs,
) -> list[Any]:
) -> dict:
"""解析参数
参数:
@ -202,31 +212,30 @@ class ShopManage:
param: ShopParam
返回:
list[Any]: 参数
dict: 参数
"""
param_list = []
_bot = param.bot
param.bot = None
param_json = param.dict()
param_json["bot"] = _bot
for par in args.keys():
if par in ["shop_param"]:
param_list.append(param)
elif par in ["session"]:
param_list.append(session)
elif par in ["message"]:
param_list.append(kwargs.get("message"))
elif par not in ["args", "kwargs"]:
param_list.append(param_json.get(par))
if kwargs.get(par) is not None:
del kwargs[par]
return param_list
param_json = {
"bot": _bot,
"kwargs": kwargs,
**param.to_dict(),
**param.extra_data,
"session": session,
"message": message,
}
for key in list(param_json.keys()):
if key not in args:
del param_json[key]
return param_json
@classmethod
async def run_before_after(
cls,
goods: Goods,
param: ShopParam,
session: Uninfo,
message: UniMsg,
run_type: Literal["after", "before"],
**kwargs,
):
@ -240,16 +249,19 @@ class ShopManage:
fun_list = goods.before_handle if run_type == "before" else goods.after_handle
if fun_list:
for func in fun_list:
args = inspect.signature(func).parameters
if args and next(iter(args.keys())) != "kwargs":
if args := inspect.signature(func).parameters:
if asyncio.iscoroutinefunction(func):
await func(*cls.__parse_args(args, param, **kwargs))
await func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
else:
func(*cls.__parse_args(args, param, **kwargs))
func(
**cls.__parse_args(args, param, session, message, **kwargs)
)
elif asyncio.iscoroutinefunction(func):
await func(**kwargs)
await func()
else:
func(**kwargs)
func()
@classmethod
async def __run(
@ -257,6 +269,7 @@ class ShopManage:
goods: Goods,
param: ShopParam,
session: Uninfo,
message: UniMsg,
**kwargs,
) -> str | UniMessage | None:
"""运行道具函数
@ -270,18 +283,20 @@ class ShopManage:
"""
args = inspect.signature(goods.func).parameters # type: ignore
if goods.func:
if args and next(iter(args.keys())) != "kwargs":
if args:
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)
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):
return await goods.func(
**kwargs,
)
return await goods.func()
else:
return goods.func(**kwargs)
return goods.func()
@classmethod
async def use(
@ -329,12 +344,12 @@ class ShopManage:
)
if num > param.max_num_limit:
return f"{goods_info.goods_name} 单次使用最大数量为{param.max_num_limit}..."
await cls.run_before_after(goods, param, "before", **kwargs)
result = await cls.__run(goods, param, session, **kwargs)
await cls.run_before_after(goods, param, session, message, "before", **kwargs)
result = await cls.__run(goods, param, session, message, **kwargs)
await UserConsole.use_props(
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:
result = f"使用道具 {goods.name} {num} 次成功!"
return result
@ -366,10 +381,14 @@ class ShopManage:
"""
if uuid in cls.uuid2goods:
raise ValueError("该商品使用函数已被注册!")
kwargs["send_success_msg"] = send_success_msg
kwargs["max_num_limit"] = max_num_limit
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,
before_handle=before_handle,
after_handle=after_handle,
@ -392,17 +411,19 @@ class ShopManage:
返回:
str: 返回小
"""
if name == "神秘药水":
return "你们看看就好啦,这是不可能卖给你们的~"
if num < 0:
return "购买的数量要大于0!"
goods_list = await GoodsInfo.annotate().order_by("id").all()
goods_list = [
goods
for goods in goods_list
if goods.goods_limit_time > time.time() or goods.goods_limit_time == 0
]
goods_list = (
await GoodsInfo.filter(
Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
)
.annotate()
.order_by("id")
.all()
)
if name.isdigit():
if int(name) > len(goods_list) or int(name) <= 0:
return "道具编号不存在..."
goods = goods_list[int(name) - 1]
elif filter_goods := [g for g in goods_list if g.goods_name == name]:
goods = filter_goods[0]
@ -457,24 +478,42 @@ class ShopManage:
user = await UserConsole.get_user(user_id, platform)
if not user.props:
return None
result = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
data_list = []
uuid2goods = {item.uuid: item for item in result}
column_name = ["-", "使用ID", "名称", "数量", "简介"]
for i, p in enumerate(user.props):
if prop := uuid2goods.get(p):
data_list.append(
[
(ICON_PATH / prop.icon, 33, 33) if prop.icon else "",
i,
prop.goods_name,
user.props[p],
prop.goods_description,
]
)
user.props = {uuid: count for uuid, count in user.props.items() if count > 0}
goods_list = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
goods_by_uuid = {item.uuid: item for item in goods_list}
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,
i,
prop.goods_name,
user.props[prop_uuid],
prop.goods_description,
]
)
if not table_rows:
return None
column_name = ["-", "使用ID", "名称", "数量", "简介"]
return await ImageTemplate.table_page(
f"{name}的道具仓库", "", column_name, data_list
f"{name}的道具仓库",
"通过 使用道具[ID/名称] 令道具生效",
column_name,
table_rows,
)
@classmethod

View File

@ -16,18 +16,3 @@ async def _(user_id: str):
"shop",
)
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
from nonebot_plugin_htmlrender import template_to_pic
from pydantic import BaseModel
from tortoise.expressions import Q
from zhenxun.configs.config import BotConfig
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:
"""构建图片"""
goods_list: list[tuple[int, GoodsInfo]] = [
(i + 1, goods)
for i, goods in enumerate(await GoodsInfo.get_all_goods())
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time
]
goods_list = (
await GoodsInfo.filter(
Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
)
.annotate()
.order_by("id")
.all()
)
partition_dict: dict[str, list[dict]] = {}
for goods in goods_list:
if not goods[1].partition:
goods[1].partition = "默认分区"
if goods[1].partition not in partition_dict:
partition_dict[goods[1].partition] = []
for idx, goods in enumerate(goods_list):
if not goods.partition:
goods.partition = "默认分区"
if goods.partition not in partition_dict:
partition_dict[goods.partition] = []
icon = None
if goods[1].icon:
path = ICON_PATH / goods[1].icon
if goods.icon:
path = ICON_PATH / goods.icon
if path.exists():
icon = (
"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],
"price": goods[1].goods_price,
"daily_limit": goods[1].daily_limit or "",
"name": goods[1].goods_name,
"id": idx + 1,
"price": goods.goods_price,
"discount_price": get_discount(goods.goods_price, goods.goods_discount),
"limit_time": get_limit_time(goods.goods_limit_time),
"daily_limit": goods.daily_limit or "",
"name": goods.goods_name,
"icon": icon,
"description": goods[1].goods_description,
"description": goods.goods_description,
}
)
data_list = [

View File

@ -1,5 +1,7 @@
import time
from tortoise.expressions import Q
from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.models.goods_info import GoodsInfo
from zhenxun.utils._build_image import BuildImage
@ -14,17 +16,19 @@ async def normal_image() -> bytes:
返回:
BuildImage: 商店图片
"""
goods_lst = await GoodsInfo.get_all_goods()
h = 10
_list: list[GoodsInfo] = [
goods
for goods in goods_lst
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time
]
goods_list = (
await GoodsInfo.filter(
Q(goods_limit_time__gte=time.time()) | Q(goods_limit_time=0)
)
.annotate()
.order_by("id")
.all()
)
# A = BuildImage(1100, h, color="#f9f6f2")
total_n = 0
image_list = []
for idx, goods in enumerate(_list):
for idx, goods in enumerate(goods_list):
name_image = BuildImage(
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_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.utils.depends import UserName
from zhenxun.utils.message import MessageUtils
@ -37,6 +42,12 @@ __plugin_meta__ = PluginMetadata(
extra=PluginExtraData(
author="HibiKier",
version="0.1",
commands=[
Command(command="签到"),
Command(command="我的签到"),
Command(command="签到排行"),
Command(command="签到总排行"),
],
configs=[
RegisterConfig(
module="send_setu",
@ -82,7 +93,7 @@ __plugin_meta__ = PluginMetadata(
),
],
limits=[PluginCdBlock()],
).dict(),
).to_dict(),
)

View File

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

View File

@ -16,6 +16,7 @@ from zhenxun.models.sign_log import SignLog
from zhenxun.models.sign_user import SignUser
from zhenxun.utils.http_utils import AsyncHttpx
from zhenxun.utils.image_utils import BuildImage
from zhenxun.utils.platform import PlatformUtils
from .config import (
SIGN_BACKGROUND_PATH,
@ -430,7 +431,9 @@ async def _generate_html_card(
)
now = datetime.now()
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,
"uid": uid,
"sign_count": f"{user.sign_count}",

View File

@ -10,7 +10,7 @@ from nonebot_plugin_alconna import (
)
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.message import MessageUtils
@ -45,7 +45,16 @@ __plugin_meta__ = PluginMetadata(
"全局周功能调用统计",
"全局月功能调用统计",
""".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(),
extra=PluginExtraData(
author="HibiKier", version="0.1", plugin_type=PluginType.HIDDEN
).dict(),
).to_dict(),
)
TEMP_LIST = []

View File

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

View File

@ -5,6 +5,7 @@ from nonebot.adapters import Bot
from nonebot.params import Command
from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import Text as alcText
from nonebot_plugin_alconna import UniMsg
from nonebot_plugin_session import EventSession
@ -38,10 +39,12 @@ __plugin_meta__ = PluginMetadata(
)
],
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()

View File

@ -1,11 +1,8 @@
import asyncio
import random
from nonebot.adapters import Bot
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_session import EventSession
@ -59,6 +56,7 @@ class BroadcastManage:
session=session,
target=f"{group.group_id}:{group.channel_id}",
)
await asyncio.sleep(random.randint(1, 3))
else:
logger.warning("target为空", "广播", session=session)
except Exception as e:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@ from nonebot_plugin_alconna import (
)
from nonebot_plugin_session import EventSession
from zhenxun.configs.config import BotConfig
from zhenxun.configs.path_config import IMAGE_PATH
from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.fg_request import FgRequest
@ -46,7 +47,7 @@ __plugin_meta__ = PluginMetadata(
author="HibiKier",
version="0.1",
plugin_type=PluginType.SUPERUSER,
).dict(),
).to_dict(),
)
@ -134,14 +135,15 @@ async def _(
"r": RequestHandleType.REFUSED,
"i": RequestHandleType.IGNORE,
}
req = None
handle_type = type_dict[handle[-1]]
try:
if handle_type == RequestHandleType.APPROVE:
await FgRequest.approve(bot, id)
req = await FgRequest.approve(bot, id)
if handle_type == RequestHandleType.REFUSED:
await FgRequest.refused(bot, id)
req = await FgRequest.refused(bot, id)
if handle_type == RequestHandleType.IGNORE:
await FgRequest.ignore(id)
req = await FgRequest.ignore(id)
except NotFoundError:
await MessageUtils.build_message("未发现此id的请求...").finish(reply_to=True)
except Exception:
@ -149,7 +151,14 @@ async def _(
reply_to=True
)
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()

View File

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

View File

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

View File

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

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