Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b65ac2126 | ||
|
|
3611678e13 |
@@ -1,15 +0,0 @@
|
||||
.devcontainer/
|
||||
.github/
|
||||
.vscode/
|
||||
assets/
|
||||
k8s/
|
||||
tests/
|
||||
.dockerignore
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.pre-commit-config.yaml
|
||||
.prettier*
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
LICENSE
|
||||
*.md
|
||||
@@ -10,52 +10,7 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
|
||||
|
||||
SESSION_EXPIRE_TIMEOUT=30
|
||||
|
||||
# 全局图片统一使用bytes发送,当真寻与协议端不在同一服务器上时为True
|
||||
IMAGE_TO_BYTES = False
|
||||
|
||||
PLATFORM_SUPERUSERS = '
|
||||
{
|
||||
"qq": [""],
|
||||
"dodo": [""]
|
||||
}
|
||||
'
|
||||
|
||||
DRIVER=~fastapi+~httpx+~websockets
|
||||
|
||||
# kook adapter toekn
|
||||
# kaiheila_bots =[{"token": ""}]
|
||||
|
||||
# # discode adapter
|
||||
# DISCORD_BOTS='
|
||||
# [
|
||||
# {
|
||||
# "token": "",
|
||||
# "intent": {
|
||||
# "guild_messages": true,
|
||||
# "direct_messages": true
|
||||
# },
|
||||
# "application_commands": {"*": ["*"]}
|
||||
# }
|
||||
# ]
|
||||
# '
|
||||
# DISCORD_PROXY=''
|
||||
|
||||
# # dodo adapter
|
||||
# DODO_BOTS='
|
||||
# [
|
||||
# {
|
||||
# "client_id": "",
|
||||
# "token": ""
|
||||
# }
|
||||
# ]
|
||||
# '
|
||||
|
||||
# application_commands的{"*": ["*"]}代表将全部应用命令注册为全局应用命令
|
||||
# {"admin": ["123", "456"]}则代表将admin命令注册为id是123、456服务器的局部命令,其余命令不注册
|
||||
|
||||
# LOG_LEVEL=DEBUG
|
||||
DEBUG=true
|
||||
# 服务器和端口
|
||||
HOST = 127.0.0.1
|
||||
PORT = 8080
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
name: Issue template
|
||||
about: " issue template's purpose here."
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### 系统版本:Ubuntu 20.04
|
||||
### 真寻版本:0.1.5.3
|
||||
|
||||
### 错误截图
|
||||
|
||||
[img]
|
||||
|
||||
### 日志截图
|
||||
|
||||
[img]
|
||||
|
||||
### 错误说明
|
||||
|
||||
发生了xx错误...
|
||||
@@ -1,9 +0,0 @@
|
||||
### 系统版本:Ubuntu 20.04
|
||||
### 真寻版本:0.1.5.3
|
||||
|
||||
### 错误截图
|
||||
|
||||
[img]
|
||||
|
||||
### 错误说明
|
||||
发生了xx错误...
|
||||
@@ -1,184 +0,0 @@
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
demo.py
|
||||
test.py
|
||||
server_ip.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
csgo/
|
||||
fantasy_card/
|
||||
data/
|
||||
log/
|
||||
backup/
|
||||
extensive_plugin/
|
||||
test/
|
||||
bot.py
|
||||
data/
|
||||
.env
|
||||
.env.dev
|
||||
/resources/text/
|
||||
# /resources/image/
|
||||
/resources/temp/
|
||||
/resources/image/genshin/
|
||||
/resources/image/draw_card/
|
||||
/resources/image/card/
|
||||
/resources/image/temp/
|
||||
/resources/image/sign/today_card/
|
||||
/resources/image/image_management/
|
||||
/resources/image/bilibili_sub/
|
||||
/resources/image/other/
|
||||
/resources/image/_setu/
|
||||
/resources/image/_r18/
|
||||
/resources/image/csgo_cases/
|
||||
!/resources/image/csgo_cases/_background/
|
||||
/resources/image/superuser_help.png
|
||||
/resources/image/update_img_help.png
|
||||
/resources/image/prts/
|
||||
/configs/config.py
|
||||
configs/config.yaml
|
||||
./.env
|
||||
./.env.dev
|
||||
plugins/csgo_server/
|
||||
plugins/activity/
|
||||
!/resources/image/genshin/alc/back.png
|
||||
!/data/genshin_alc/
|
||||
.vscode/launch.json
|
||||
/resources/template/my_info
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"C_Cpp.errorSquiggles": "enabled",
|
||||
"terminal.integrated.env.linux": {
|
||||
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"aiofiles",
|
||||
"Alconna",
|
||||
"arclet",
|
||||
"Arparma",
|
||||
"displayname",
|
||||
"flmt",
|
||||
"getbbox",
|
||||
"hibiapi",
|
||||
"httpx",
|
||||
"kaiheila",
|
||||
"lolicon",
|
||||
"nonebot",
|
||||
"onebot",
|
||||
"pixiv",
|
||||
"Setu",
|
||||
"tobytes",
|
||||
"ujson",
|
||||
"unban",
|
||||
"userinfo",
|
||||
"zhenxun"
|
||||
],
|
||||
"python.analysis.autoImportCompletions": true
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR /app/zhenxun
|
||||
|
||||
COPY . /app/zhenxun
|
||||
|
||||
RUN pip install poetry -i https://mirrors.aliyun.com/pypi/simple/
|
||||
|
||||
RUN poetry install
|
||||
|
||||
VOLUME /app/zhenxun/data /app/zhenxun/data
|
||||
|
||||
VOLUME /app/zhenxun/resources /app/zhenxun/resources
|
||||
|
||||
RUN poetry run playwright install --with-deps chromium
|
||||
|
||||
CMD ["poetry", "run", "python", "bot.py"]
|
||||
@@ -1,5 +1,5 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -7,15 +7,17 @@
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
@@ -24,34 +26,44 @@ them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
@@ -60,7 +72,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
@@ -537,45 +549,35 @@ to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
@@ -633,29 +635,40 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
__version__: v0.2
|
||||
@@ -1,26 +1,19 @@
|
||||
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 zhenxun.services.db_context import disconnect, init
|
||||
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
|
||||
from services.db_context import init, disconnect
|
||||
|
||||
nonebot.init()
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter(OneBotV11Adapter)
|
||||
driver.register_adapter(KaiheilaAdapter)
|
||||
driver.register_adapter(DoDoAdapter)
|
||||
# driver.register_adapter(DiscordAdapter)
|
||||
|
||||
|
||||
driver.register_adapter("cqhttp", CQHTTPBot)
|
||||
config = driver.config
|
||||
driver.on_startup(init)
|
||||
driver.on_shutdown(disconnect)
|
||||
|
||||
nonebot.load_builtin_plugins("echo") # 内置插件
|
||||
nonebot.load_plugins("zhenxun/builtin_plugins")
|
||||
nonebot.load_plugins("zhenxun/plugins")
|
||||
nonebot.load_builtin_plugins()
|
||||
nonebot.load_plugins("plugins")
|
||||
nonebot.load_plugins("plugins/shop")
|
||||
nonebot.load_plugins("plugins/genshin")
|
||||
nonebot.load_plugins("plugins/alapi")
|
||||
nonebot.load_plugins("plugins/pix_gallery")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
from .utils.util import get_config_data
|
||||
from typing import List, Optional, Tuple
|
||||
from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
# 是否使用配置文件
|
||||
USE_CONFIG_FILE: bool = False
|
||||
|
||||
|
||||
# API KEY(必要)
|
||||
RSSHUBAPP: str = "https://rsshub.app" # rsshub
|
||||
ALAPI_TOKEN: str = "" # ALAPI https://admin.alapi.cn/user/login
|
||||
HIBIAPI: str = "https://api.obfs.dev"
|
||||
# 图灵
|
||||
TL_KEY: List[str] = []
|
||||
|
||||
# 数据库(必要)
|
||||
# 如果填写了bind就不需要再填写后面的字段了#)
|
||||
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
|
||||
bind: str = "" # 数据库连接链接
|
||||
sql_name: str = "postgresql"
|
||||
user: str = "" # 数据用户名
|
||||
password: str = "" # 数据库密码
|
||||
address: str = "" # 数据库地址
|
||||
port: str = "" # 数据库端口
|
||||
database: str = "" # 数据库名称
|
||||
|
||||
# 代理
|
||||
SYSTEM_PROXY: Optional[str] = None # 全局代理
|
||||
BUFF_PROXY: Optional[str] = None # Buff代理
|
||||
|
||||
# 公开图库列表
|
||||
IMAGE_DIR_LIST: List[str] = ["色图", "美图", "萝莉", "壁纸"]
|
||||
|
||||
# 对被ban用户发送的消息
|
||||
BAN_RESULT: str = "才不会给你发消息."
|
||||
|
||||
|
||||
# 插件配置
|
||||
MAXINFO_REIMU: int = 7 # 上车(reimu)功能查找目的地的最大数
|
||||
COUNT_PER_DAY_REIMU: int = 5 # 每日上车(reimu)次数限制
|
||||
MAXINFO_BT: int = 10 # bt功能单次查找最大数
|
||||
MAXINFO_PRIVATE_ANIME: int = 20 # 私聊搜索动漫返回的最大数量
|
||||
MAXINFO_GROUP_ANIME: int = 5 # 群搜索动漫返回的最大数量
|
||||
MAX_FIND_IMG_COUNT: int = 3 # 识图最大返回数
|
||||
# 参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)
|
||||
WITHDRAW_SETU_TIME: Tuple[int, int] = (0, 1)
|
||||
|
||||
# 各种卡池的开关
|
||||
PRTS_FLAG = True # 明日方舟
|
||||
GENSHIN_FLAG = True # 原神
|
||||
PRETTY_FLAG = True # 赛马娘
|
||||
GUARDIAN_FLAG = True # 坎公骑冠剑
|
||||
PCR_FLAG = True # 公主连结
|
||||
AZUR_FLAG = True # 碧蓝航线
|
||||
FGO_FLAG = True # 命运-冠位指定(FGO)
|
||||
ONMYOJI_FLAG = True # 阴阳师
|
||||
|
||||
PCR_TAI = True # pcr是否开启台服卡池
|
||||
SEMAPHORE = 5 # 限制碧蓝航线和FGO并发数
|
||||
|
||||
ADMIN_DEFAULT_AUTH: int = 5 # 默认群管理员权限
|
||||
|
||||
MAX_SIGN_GOLD: int = 200 # 签到好感度加成额外获得的最大金币数
|
||||
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
|
||||
|
||||
INITIAL_SETU_PROBABILITY: float = 0.7 # 色图概率
|
||||
FUDU_PROBABILITY: float = 0.7 # 复读概率
|
||||
|
||||
INITIAL_OPEN_CASE_COUNT: int = 20 # 初始开箱次数
|
||||
MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数
|
||||
MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间
|
||||
MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟)
|
||||
|
||||
# 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟
|
||||
MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长(分钟)
|
||||
MALICIOUS_BAN_COUNT: int = 8 # 恶意命令触发检测最大触发次数
|
||||
MALICIOUS_CHECK_TIME: int = 5 # 恶意命令触发检测规定时间内(秒)
|
||||
|
||||
# LEVEL
|
||||
DELETE_IMG_LEVEL: int = 7 # 删除图片权限
|
||||
MOVE_IMG_LEVEL: int = 7 # 移动图片权限
|
||||
UPLOAD_LEVEL: int = 6 # 上传图片权限
|
||||
BAN_LEVEL: int = 5 # BAN权限
|
||||
OC_LEVEL: int = 2 # 开关群功能权限
|
||||
MUTE_LEVEL: int = 5 # 更改禁言设置权限
|
||||
MEMBER_ACTIVITY_LEVEL = 5 # 群员活跃检测设置权限
|
||||
|
||||
# 是否开启HIBIAPI搜图功能(该功能会搜索群友提交的xp)
|
||||
HIBIAPI_FLAG: bool = True
|
||||
# HIBIAPI搜图图片的最低收藏
|
||||
HIBIAPI_BOOKMARKS: int = 5000
|
||||
|
||||
# 需要为哪些群更新最新版gocq吗?(上传最新版gocq)
|
||||
# 示例:[434995955, 239483248]
|
||||
UPDATE_GOCQ_GROUP: List[int] = []
|
||||
|
||||
# 是否存储色图
|
||||
DOWNLOAD_SETU: bool = True
|
||||
# 仅仅使用本地色图
|
||||
ONLY_USE_LOCAL_SETU: bool = False
|
||||
# 是否自动同意好友添加
|
||||
AUTO_ADD_FRIEND: bool = True
|
||||
# 当含有ALAPI_TOKEN时是否检测文本合规,开启检测会减慢回复速度
|
||||
ALAPI_AI_CHECK: bool = True
|
||||
# 导入商店自带的三个商品
|
||||
IMPORT_DEFAULT_SHOP_GOODS: bool = True
|
||||
# 真寻是否自动更新
|
||||
AUTO_UPDATE_ZHENXUN: bool = True
|
||||
|
||||
# 群管理员功能 与 对应权限
|
||||
admin_plugins_auth = {
|
||||
"admin_bot_manage": OC_LEVEL,
|
||||
"ban": BAN_LEVEL,
|
||||
"delete_img": DELETE_IMG_LEVEL,
|
||||
"move_img": MOVE_IMG_LEVEL,
|
||||
"upload_img": UPLOAD_LEVEL,
|
||||
"admin_help": 1,
|
||||
"mute": MUTE_LEVEL,
|
||||
"member_activity_handle": MEMBER_ACTIVITY_LEVEL,
|
||||
}
|
||||
|
||||
|
||||
# 模块与对应命令和对应群权限
|
||||
# 用于生成帮助图片 和 开关功能
|
||||
plugins2info_dict = {
|
||||
"sign_in": {"level": 5, "cmd": ["签到"]},
|
||||
"send_img": {"level": 5, "cmd": ["发送图片", "发图", "萝莉", "美图", "壁纸"]},
|
||||
"send_setu": {"level": 9, "cmd": ["色图", "涩图", "瑟图", "查色图"]},
|
||||
"white2black": {"level": 5, "cmd": ["黑白图", "黑白草图"]},
|
||||
"coser": {"level": 9, "cmd": ["coser", "cos"]},
|
||||
"quotations": {"level": 5, "cmd": ["语录"]},
|
||||
"jitang": {"level": 5, "cmd": ["鸡汤"]},
|
||||
"send_dinggong_voice": {"level": 5, "cmd": ["骂我", "骂老子", "骂劳资"]},
|
||||
"open_cases": {"level": 5, "cmd": ["开箱", "我的开箱", "群开箱统计", "我的金色"]},
|
||||
"luxun": {"level": 5, "cmd": ["鲁迅说", "鲁迅说过"]},
|
||||
"fake_msg": {"level": 5, "cmd": ["假消息"]},
|
||||
"buy": {"level": 5, "cmd": ["购买", "购买道具"]},
|
||||
"my_gold": {"level": 5, "cmd": ["我的金币"]},
|
||||
"my_props": {"level": 5, "cmd": ["我的道具"]},
|
||||
"shop_handle": {"level": 5, "cmd": ["商店"]},
|
||||
"update_pic": {"level": 5, "cmd": ["图片", "操作图片", "修改图片"]},
|
||||
"search_buff_skin_price": {"level": 5, "cmd": ["查询皮肤"]},
|
||||
"weather": {"level": 5, "cmd": ["天气", "查询天气", "天气查询"]},
|
||||
"yiqing": {"level": 5, "cmd": ["疫情", "疫情查询", "查询疫情"]},
|
||||
"what_anime": {"level": 5, "cmd": ["识番"]},
|
||||
"search_anime": {"level": 5, "cmd": ["搜番"]},
|
||||
"songpicker2": {"level": 5, "cmd": ["点歌"]},
|
||||
"epic": {"level": 5, "cmd": ["epic"]},
|
||||
"pixiv": {"level": 9, "cmd": ["pixiv", "p站排行", "搜图"]},
|
||||
"poke": {"level": 5, "cmd": ["戳一戳", "拍一拍"]},
|
||||
"draw_card": {
|
||||
"level": 5,
|
||||
"cmd": [
|
||||
"抽卡",
|
||||
"游戏抽卡",
|
||||
"原神抽卡",
|
||||
"方舟抽卡",
|
||||
"坎公骑冠剑抽卡",
|
||||
"pcr抽卡",
|
||||
"fgo抽卡",
|
||||
"碧蓝抽卡",
|
||||
"碧蓝航线抽卡",
|
||||
"阴阳师抽卡",
|
||||
],
|
||||
},
|
||||
"ai": {"level": 5, "cmd": ["ai", "Ai", "AI", "aI"]},
|
||||
"one_friend": {"level": 5, "cmd": ["我有一个朋友", "我有一个朋友想问问"]},
|
||||
"translate": {"level": 5, "cmd": ["翻译", "英翻", "翻英", "日翻", "翻日", "韩翻", "翻韩"]},
|
||||
"nonebot_plugin_picsearcher": {"level": 5, "cmd": ["识图"]},
|
||||
"almanac": {"level": 5, "cmd": ["原神黄历", "黄历"]},
|
||||
"material_remind": {"level": 5, "cmd": ["今日素材", "天赋材料"]},
|
||||
"qiu_qiu_translation": {"level": 5, "cmd": ["丘丘翻译", "丘丘一下", "丘丘语翻译"]},
|
||||
"query_resource_points": {"level": 5, "cmd": ["原神资源查询", "原神资源列表"]},
|
||||
"russian": {"level": 5, "cmd": ["俄罗斯轮盘", "俄罗斯转盘", "装弹"]},
|
||||
"gold_redbag": {"level": 5, "cmd": ["塞红包", "红包", "抢红包"]},
|
||||
"poetry": {"level": 5, "cmd": ["念诗", "来首诗", "念首诗"]},
|
||||
"comments_163": {"level": 5, "cmd": ["到点了", "12点了", "网易云热评", "网易云评论"]},
|
||||
"cover": {"level": 5, "cmd": ["b封面", "B封面"]},
|
||||
"pid_search": {"level": 9, "cmd": ["p搜", "P搜"]},
|
||||
"pix": {
|
||||
"level": 5,
|
||||
"cmd": ["pix", "PIX", "pIX", "Pix", "PIx"],
|
||||
},
|
||||
}
|
||||
|
||||
if TL_M_KEY:
|
||||
TL_KEY = TL_M_KEY
|
||||
if SYSTEM_M_PROXY:
|
||||
SYSTEM_PROXY = SYSTEM_M_PROXY
|
||||
if ALAPI_M_TOKEN:
|
||||
ALAPI_TOKEN = ALAPI_M_TOKEN
|
||||
|
||||
|
||||
HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
|
||||
RSSHUBAPP = RSSHUBAPP[:-1] if RSSHUBAPP[-1] == "/" else RSSHUBAPP
|
||||
|
||||
# 配置文件应用
|
||||
# if USE_CONFIG_FILE:
|
||||
# config = get_config_data()
|
||||
# if config:
|
||||
# for key in config.keys():
|
||||
# if isinstance(config[key], str):
|
||||
# config[key] = config[key].strip()
|
||||
# if key.find("proxy") != -1:
|
||||
# if not config[key]:
|
||||
# config[key] = None
|
||||
# # if not configs[key] and key.find("PATH") == -1:
|
||||
# # configs[key] = None
|
||||
# globals().update(config)
|
||||
@@ -0,0 +1,62 @@
|
||||
from .utils.util import get_config_data
|
||||
from pathlib import Path
|
||||
from configs.config import USE_CONFIG_FILE
|
||||
|
||||
# 图片路径
|
||||
IMAGE_PATH = Path("resources/img/")
|
||||
# 音频路径
|
||||
VOICE_PATH = Path("resources/voice/")
|
||||
# 文本路径
|
||||
TXT_PATH = Path("resources/txt/")
|
||||
# 日志路径
|
||||
LOG_PATH = Path("log/")
|
||||
# 字体路径
|
||||
TTF_PATH = Path("resources/ttf/")
|
||||
# 数据路径
|
||||
DATA_PATH = Path("data/")
|
||||
# 临时图片路径
|
||||
TEMP_PATH = Path("resources/img/temp/")
|
||||
|
||||
|
||||
def init_path():
|
||||
global IMAGE_PATH, VOICE_PATH, TXT_PATH, LOG_PATH, TTF_PATH, DATA_PATH, TEMP_PATH
|
||||
if USE_CONFIG_FILE:
|
||||
data = get_config_data()
|
||||
if data.get('IMAGE_PATH'):
|
||||
IMAGE_PATH = Path(data['IMAGE_PATH'])
|
||||
if data.get('VOICE_PATH'):
|
||||
VOICE_PATH = Path(data['VOICE_PATH'])
|
||||
if data.get('TXT_PATH'):
|
||||
TXT_PATH = Path(data['TXT_PATH'])
|
||||
if data.get('LOG_PATH'):
|
||||
LOG_PATH = Path(data['LOG_PATH'])
|
||||
if data.get('TTF_PATH'):
|
||||
TTF_PATH = Path(data['TTF_PATH'])
|
||||
if data.get('DATA_PATH'):
|
||||
DATA_PATH = Path(data['DATA_PATH'])
|
||||
if data.get('DRAW_PATH'):
|
||||
DRAW_PATH = Path(data['DRAW_PATH'])
|
||||
if data.get('TEMP_PATH'):
|
||||
TEMP_PATH = Path(data['TEMP_PATH'])
|
||||
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
VOICE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TXT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TTF_PATH.mkdir(parents=True, exist_ok=True)
|
||||
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
|
||||
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
|
||||
TXT_PATH = str(TXT_PATH.absolute()) + '/'
|
||||
LOG_PATH = str(LOG_PATH.absolute()) + '/'
|
||||
TTF_PATH = str(TTF_PATH.absolute()) + '/'
|
||||
DATA_PATH = str(DATA_PATH.absolute()) + '/'
|
||||
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
|
||||
|
||||
|
||||
init_path()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(IMAGE_PATH)
|
||||
@@ -0,0 +1,176 @@
|
||||
# import nonebot
|
||||
from pathlib import Path
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
# driver: nonebot.Driver = nonebot.get_driver()
|
||||
|
||||
base_config = Path() / 'config.json'
|
||||
plugins_cmd_config = Path() / 'configs' / 'plugins2cmd_config.json'
|
||||
plugins_setting = Path() / 'configs' / 'plugins_setting.json'
|
||||
|
||||
|
||||
def init_config():
|
||||
if not base_config.exists():
|
||||
base_config.parent.mkdir(parents=True, exist_ok=True)
|
||||
config_dict = {
|
||||
'apikey': {
|
||||
'LOLICON_KEY': '',
|
||||
'TL_KEY': [],
|
||||
},
|
||||
'sql': {
|
||||
'bind': '',
|
||||
'sql_name': '',
|
||||
'user': '',
|
||||
'password': '',
|
||||
'address': '',
|
||||
'port': '',
|
||||
'database': '',
|
||||
},
|
||||
'path': {
|
||||
'IMAGE_PATH': '',
|
||||
'VOICE_PATH': '',
|
||||
'TXT_PATH': '',
|
||||
'LOG_PATH': '',
|
||||
'DATA_PATH': '',
|
||||
'DRAW_PATH': '',
|
||||
'TEMP_PATH': '',
|
||||
},
|
||||
'proxy': {
|
||||
'system_proxy': '',
|
||||
'buff_proxy': ''
|
||||
},
|
||||
'level': {
|
||||
'DELETE_IMG_LEVEL': 7,
|
||||
'MOVE_IMG_LEVEL': 7,
|
||||
'UPLOAD_LEVEL': 6,
|
||||
'BAN_LEVEL': 5,
|
||||
'OC_LEVEL': 2,
|
||||
'MUTE_LEVEL': 5,
|
||||
},
|
||||
'auth': {
|
||||
'ADMIN_DEFAULT_AUTH': 5,
|
||||
'admin_plugins_auth': {
|
||||
"admin_bot_manage": 2,
|
||||
"ban": 5,
|
||||
"delete_img": 7,
|
||||
"move_img": 7,
|
||||
"upload_img": 6,
|
||||
"admin_help": 1,
|
||||
"mute": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
with open(base_config, 'w', encoding='utf8') as f:
|
||||
json.dump(config_dict, f, indent=4, ensure_ascii=False)
|
||||
if not plugins_cmd_config.exists():
|
||||
plugins_cmd_config.parent.mkdir(parents=True, exist_ok=True)
|
||||
config_dict = {
|
||||
'base_config': {
|
||||
'sign_in': ['签到'],
|
||||
'send_img': ['发送图片', '萝莉', '美图', '壁纸'],
|
||||
'send_setu': ['色图', '涩图', '瑟图', '查色图'],
|
||||
'white2black': ['黑白图', '黑白草图'],
|
||||
'coser': ['coser', 'cos'],
|
||||
'quotations': ['语录'],
|
||||
'jitang': ['鸡汤'],
|
||||
'send_dinggong_voice': ['骂我', '骂老子', '骂劳资'],
|
||||
'open_cases': ['开箱', '我的开箱', '群开箱统计', '我的金色'],
|
||||
'luxun': ['鲁迅说过', '鲁迅说'],
|
||||
'fake_msg': ['假消息'],
|
||||
'buy': ['购买', '购买道具'],
|
||||
'my_gold': ['我的金币'],
|
||||
'my_props': ['我的道具'],
|
||||
'shop_handle': ['商店'],
|
||||
'nonebot_plugin_cocdicer': ['骰子娘'],
|
||||
'update_pic': ['图片', '操作图片', '修改图片'],
|
||||
'search_buff_skin_price': ['查询皮肤'],
|
||||
'weather': ['天气', '查询天气', '天气查询'],
|
||||
'yiqing': ['疫情', '疫情查询', '查询疫情'],
|
||||
'what_anime': ['识番'],
|
||||
'search_anime': ['搜番'],
|
||||
'songpicker2': ['点歌'],
|
||||
'epic': ['epic'],
|
||||
'pixiv': ['pixiv', 'p站排行', '搜图'],
|
||||
'poke': ['戳一戳'],
|
||||
'draw_card': ['游戏抽卡', '原神一井', '原神来一井', '方舟一井', '方舟来一井'],
|
||||
'ai': ['ai', 'Ai', 'AI', 'aI'],
|
||||
'one_friend': ['我有一个朋友', '我有一个朋友想问问'],
|
||||
'translate': ['翻译', '英翻', '翻英', '日翻', '翻日', '韩翻', '翻韩'],
|
||||
'nonebot_plugin_picsearcher': ['识图'],
|
||||
'almanac': ['原神黄历', '黄历'],
|
||||
'material_remind': ['今日素材', '天赋材料'],
|
||||
'qiu_qiu_translation': ['丘丘翻译', '丘丘一下', '丘丘语翻译'],
|
||||
'query_resource_points': ['原神资源查询', '原神资源列表'],
|
||||
}
|
||||
}
|
||||
with open(plugins_cmd_config, 'w', encoding='utf8') as f:
|
||||
json.dump(config_dict, f, indent=4, ensure_ascii=False)
|
||||
if not plugins_setting.exists():
|
||||
plugins_setting.parent.mkdir(parents=True, exist_ok=True)
|
||||
config_dict = {
|
||||
'base': {
|
||||
'IMAGE_DIR_LIST': ["色图", "美图", "萝莉", "壁纸"],
|
||||
'BAN_RESULT': "才不会给你发消息.",
|
||||
},
|
||||
'draw_card': {
|
||||
'PRTS_FLAG': True, # 明日方舟
|
||||
'GENSHIN_FLAG': True, # 原神
|
||||
'PRETTY_FLAG': True, # 赛马娘
|
||||
'GUARDIAN_FLAG': True, # 坎公骑冠剑
|
||||
'PCR_FLAG': True, # 公主连结
|
||||
'AZUR_FLAG': True, # 碧蓝航线
|
||||
'FGO_FLAG': True, # 命运-冠位指定(FGO)
|
||||
'ONMYOJI_FLAG': True, # 阴阳师
|
||||
|
||||
'PCR_TAI': False # pcr是否开启台服卡池
|
||||
},
|
||||
'fudu': {
|
||||
'FUDU_PROBABILITY': 0.7,
|
||||
},
|
||||
'reimu': {
|
||||
'MAXINFO_REIMU': 7,
|
||||
'COUNT_PER_DAY_REIMU': 5,
|
||||
},
|
||||
'bt': {
|
||||
'MAXINFO_BT': 10,
|
||||
},
|
||||
'search_anime': {
|
||||
'MAXINFO_PRIVATE_ANIME': 20,
|
||||
'MAXINFO_GROUP_ANIME': 5,
|
||||
},
|
||||
'picsearcher': {
|
||||
'MAX_FIND_IMG_COUNT': 3,
|
||||
},
|
||||
'sign': {
|
||||
'MAX_SIGN_GOLD': 200,
|
||||
},
|
||||
'send_setu': {
|
||||
'INITIAL_SETU_PROBABILITY': 0.7,
|
||||
'MAX_SETU_R_COUNT': 5,
|
||||
'DOWNLOAD_SETU': True,
|
||||
},
|
||||
'malicious_ban': {
|
||||
'MALICIOUS_BAN_TIME': 30,
|
||||
'MALICIOUS_BAN_COUNT': 8,
|
||||
'MALICIOUS_CHECK_TIME': 5,
|
||||
},
|
||||
'open_case': {
|
||||
'INITIAL_OPEN_CASE_COUNT': 20,
|
||||
},
|
||||
'mute': {
|
||||
'MUTE_DEFAULT_COUNT': 10,
|
||||
'MUTE_DEFAULT_TIME': 7,
|
||||
'MUTE_DEFAULT_DURATION': 10,
|
||||
},
|
||||
'update_gocq': {
|
||||
'UPDATE_GOCQ_GROUP': [],
|
||||
},
|
||||
}
|
||||
with open(plugins_setting, 'w', encoding='utf8') as f:
|
||||
json.dump(config_dict, f, indent=4, ensure_ascii=False)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
from pathlib import Path
|
||||
from configs.utils.init_config import init_config
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
data: dict = {}
|
||||
|
||||
|
||||
def get_config_data():
|
||||
global data
|
||||
if not data:
|
||||
try:
|
||||
base_config = json.load(open(Path() / "config.json", 'r', encoding='utf8'))
|
||||
plugins2cmd_config = json.load(open(Path() / 'configs' / 'plugins2cmd_config.json', 'r', encoding='utf8'))
|
||||
other_config = json.load(open(Path() / 'configs' / 'other_config.json', 'r', encoding='utf8'))
|
||||
for key in base_config.keys():
|
||||
data.update(base_config[key])
|
||||
for key in plugins2cmd_config.keys():
|
||||
data.update(plugins2cmd_config[key])
|
||||
for key in other_config.keys():
|
||||
data.update(other_config[key])
|
||||
except FileNotFoundError:
|
||||
# logger.warning('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...')
|
||||
init_config()
|
||||
raise FileNotFoundError('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...')
|
||||
except ValueError:
|
||||
# logger.error('配置文件错误....')
|
||||
raise ValueError('配置文件错误....')
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 697 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 251 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 289 KiB |
|
After Width: | Height: | Size: 424 KiB |
|
After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 202 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 330 KiB |
|
After Width: | Height: | Size: 341 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 799 KiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 694 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 60 KiB |
@@ -0,0 +1,231 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
__tablename__ = "bag_users"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
gold = db.Column(db.Integer(), default=100)
|
||||
props = db.Column(db.TEXT(), nullable=False, default="")
|
||||
spend_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_today_gold = db.Column(db.Integer(), default=0)
|
||||
spend_today_gold = db.Column(db.Integer(), default=0)
|
||||
|
||||
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取金币概况
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
user = await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return (
|
||||
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
|
||||
f"\n今日收益:{user.get_today_gold - user.spend_today_gold}"
|
||||
f"\n总赚取金币:{user.get_total_gold}\n总花费金币:{user.spend_total_gold}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_gold(cls, user_qq: int, belonging_group: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取当前金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.gold
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return 100
|
||||
|
||||
@classmethod
|
||||
async def get_props(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.props
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
增加金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
花费金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
增加道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param name: 道具名称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
使用道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param name: 道具名称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有用户数据
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
query = await cls.query.gino.all()
|
||||
else:
|
||||
query = await cls.query.where((cls.belonging_group == group_id)).gino.all()
|
||||
return query
|
||||
@@ -0,0 +1,105 @@
|
||||
from services.db_context import db
|
||||
import time
|
||||
|
||||
|
||||
class BanUser(db.Model):
|
||||
__tablename__ = "ban_users"
|
||||
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
|
||||
ban_level = db.Column(db.Integer(), nullable=False)
|
||||
ban_time = db.Column(db.BigInteger())
|
||||
duration = db.Column(db.BigInteger())
|
||||
|
||||
_idx1 = db.Index("ban_group_users_idx1", "user_qq", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测ban掉目标的用户与unban用户的权限等级大小
|
||||
参数:
|
||||
:param user_qq: unban用户的qq号
|
||||
:param level: ban掉目标用户的权限等级
|
||||
"""
|
||||
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
|
||||
if not user:
|
||||
return False
|
||||
if user.ban_level > level:
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def check_ban_time(cls, user_qq: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
检测用户被ban时长
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
return ""
|
||||
if time.time() - (user.ban_time + user.duration) > 0 and user.duration != -1:
|
||||
return ""
|
||||
if user.duration == -1:
|
||||
return "∞"
|
||||
return time.time() - user.ban_time - user.duration
|
||||
|
||||
@classmethod
|
||||
async def is_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
if await cls.check_ban_time(user_qq):
|
||||
return True
|
||||
else:
|
||||
await cls.unban(user_qq)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
ban掉目标用户
|
||||
参数:
|
||||
:param user_qq: 目标用户qq号
|
||||
:param ban_level: 使用ban命令用户的权限
|
||||
:param duration: ban时长
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if not await cls.check_ban_time(user_qq):
|
||||
await cls.unban(user_qq)
|
||||
user = None
|
||||
if user is None:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
ban_level=ban_level,
|
||||
ban_time=time.time(),
|
||||
duration=duration,
|
||||
)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def unban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
unban用户
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
else:
|
||||
await cls.delete.where((cls.user_qq == user_qq)).gino.status()
|
||||
return True
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
|
||||
# 1.狂牙武器箱
|
||||
|
||||
|
||||
class BuffPrice(db.Model):
|
||||
__tablename__ = 'buff_prices'
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
case_id = db.Column(db.Integer(), nullable=False)
|
||||
skin_name = db.Column(db.Unicode(), nullable=False)
|
||||
skin_price = db.Column(db.Float(), nullable=False)
|
||||
update_date = db.Column(db.DateTime(), nullable=False)
|
||||
|
||||
_idx1 = db.Index('buff_price_idx1', 'skin_name', unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(cls, skin_name: str, for_update: bool = False) -> 'BuffPrice':
|
||||
query = cls.query.where(
|
||||
(cls.skin_name == skin_name)
|
||||
)
|
||||
if for_update:
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
return user or await cls.create(
|
||||
case_id=1,
|
||||
skin_name=skin_name,
|
||||
skin_price=0,
|
||||
update_date=datetime.min,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class UserCount(db.Model):
|
||||
__tablename__ = "count_users"
|
||||
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
|
||||
reimu_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
setu_r18_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
|
||||
_idx1 = db.Index("sign_reimu_users_idx1", "user_qq", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_count(cls, user_qq: int, name: str, count: int = 1):
|
||||
"""
|
||||
说明:
|
||||
用户添加次数
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param name: 目标名称
|
||||
:param count: 增加次数
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
user = user if user else await cls.create(user_qq=user_qq)
|
||||
if name == "reimu":
|
||||
await user.update(reimu_count=cls.reimu_count + count).apply()
|
||||
if name == "setu_r18":
|
||||
await user.update(setu_r18_count=cls.setu_r18_count + count).apply()
|
||||
|
||||
@classmethod
|
||||
async def check_count(cls, user_qq: int, name: str, max_count: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测次数是否到达最大值
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param name: 目标名称
|
||||
:param max_count: 最大值
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
user = await query.gino.first()
|
||||
user = user if user else await cls.create(user_qq=user_qq)
|
||||
if name == "reimu":
|
||||
if user.reimu_count == max_count:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if name == "setu_r18":
|
||||
if user.setu_r18_count == max_count:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def reset_count(cls):
|
||||
"""
|
||||
说明:
|
||||
重置每日次数
|
||||
"""
|
||||
for user in await cls.query.gino.all():
|
||||
await user.update(reimu_count=0, setu_r18_count=0).apply()
|
||||
@@ -0,0 +1,109 @@
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class FriendUser(db.Model):
|
||||
__tablename__ = "friend_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_id = db.Column(db.BigInteger(), nullable=False)
|
||||
user_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||
nickname = db.Column(db.Unicode())
|
||||
|
||||
_idx1 = db.Index("friend_users_idx1", "user_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_user_name(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取好友用户名称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.user_name
|
||||
else:
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加好友信息
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param user_name: 用户名称
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if not user:
|
||||
await cls.create(
|
||||
user_id=user_id,
|
||||
user_name=user_name,
|
||||
)
|
||||
else:
|
||||
await user.update(
|
||||
user_name=user_name,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_friend_info(cls, user_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除好友信息
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if user:
|
||||
await user.delete()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_friend_nickname(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取用户昵称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
return user.nickname
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置用户昵称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if not user:
|
||||
await cls.create(
|
||||
user_id=user_id,
|
||||
nickname=nickname,
|
||||
)
|
||||
else:
|
||||
await user.update(
|
||||
nickname=nickname,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
@@ -0,0 +1,129 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
class GoodsInfo(db.Model):
|
||||
__tablename__ = "goods_info"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
goods_name = db.Column(db.TEXT(), nullable=False) # 名称
|
||||
goods_price = db.Column(db.Integer(), nullable=False) # 价格
|
||||
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
|
||||
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
|
||||
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
|
||||
|
||||
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: int,
|
||||
goods_description: str,
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加商品
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时
|
||||
"""
|
||||
try:
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除商品
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
await query.delete()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def update_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: Optional[int] = None,
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
更新商品信息
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时时间
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
if goods_price:
|
||||
await query.update(goods_price=goods_price).apply()
|
||||
if goods_description:
|
||||
await query.update(goods_description=goods_description).apply()
|
||||
if goods_discount:
|
||||
await query.update(goods_discount=goods_discount).apply()
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
|
||||
"""
|
||||
说明:
|
||||
获取商品对象
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = await cls.query.where(cls.goods_name == goods_name).gino.first()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
||||
"""
|
||||
说明:
|
||||
获得全部有序商品对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
id_lst = [x.id for x in query]
|
||||
goods_lst = []
|
||||
for _ in range(len(query)):
|
||||
min_id = min(id_lst)
|
||||
goods_lst.append([x for x in query if x.id == min_id][0])
|
||||
id_lst.remove(min_id)
|
||||
return goods_lst
|
||||
@@ -0,0 +1,84 @@
|
||||
from services.db_context import db
|
||||
from typing import List
|
||||
|
||||
|
||||
class GroupInfo(db.Model):
|
||||
__tablename__ = "group_info"
|
||||
|
||||
group_id = db.Column(db.BigInteger(), nullable=False, primary_key=True)
|
||||
group_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||
max_member_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
member_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
|
||||
_idx1 = db.Index("group_info_idx1", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_group_info(cls, group_id: int) -> "GroupInfo":
|
||||
"""
|
||||
说明:
|
||||
获取群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(cls.group_id == group_id)
|
||||
return await query.gino.first()
|
||||
|
||||
@classmethod
|
||||
async def add_group_info(
|
||||
cls, group_id: int, group_name: str, max_member_count: int, member_count: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param group_name: 群名称
|
||||
:param max_member_count: 群员最大数量
|
||||
:param member_count: 群员数量
|
||||
"""
|
||||
try:
|
||||
group = (
|
||||
await cls.query.where(cls.group_id == group_id)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if group:
|
||||
await cls.update(
|
||||
group_id=group_id,
|
||||
group_name=group_name,
|
||||
max_member_count=max_member_count,
|
||||
member_count=member_count,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
group_id=group_id,
|
||||
group_name=group_name,
|
||||
max_member_count=max_member_count,
|
||||
member_count=member_count,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_group_info(cls, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
try:
|
||||
await cls.delete.where(cls.group_id == group_id).gino.status()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_group(cls) -> List["GroupInfo"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有群对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
return query
|
||||
@@ -0,0 +1,143 @@
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
from typing import List
|
||||
|
||||
|
||||
class GroupInfoUser(db.Model):
|
||||
__tablename__ = "group_info_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
user_name = db.Column(db.Unicode(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
user_join_time = db.Column(db.DateTime(), nullable=False)
|
||||
nickname = db.Column(db.Unicode())
|
||||
|
||||
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_member_info(
|
||||
cls,
|
||||
user_qq: int,
|
||||
belonging_group: int,
|
||||
user_name: str,
|
||||
user_join_time: datetime,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加群内用户信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param user_name: 用户名称
|
||||
:param user_join_time: 入群时间
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
try:
|
||||
if not await query.gino.first():
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
user_name=user_name,
|
||||
belonging_group=belonging_group,
|
||||
user_join_time=user_join_time,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_member_info(
|
||||
cls, user_qq: int, belonging_group: int
|
||||
) -> "GroupInfoUser":
|
||||
"""
|
||||
说明:
|
||||
查询群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
return await query.gino.first()
|
||||
|
||||
@classmethod
|
||||
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user is None:
|
||||
return True
|
||||
else:
|
||||
await cls.delete.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
).gino.status()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户qq
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
member_list = []
|
||||
query = cls.query.where((cls.belonging_group == belonging_group))
|
||||
for user in await query.gino.all():
|
||||
member_list.append(user.user_qq)
|
||||
return member_list
|
||||
|
||||
@classmethod
|
||||
async def set_group_member_nickname(
|
||||
cls, user_qq: int, belonging_group: int, nickname: str
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置群员在该群内的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if user:
|
||||
await user.update(nickname=nickname).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取用户在该群的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
return user.nickname
|
||||
return ""
|
||||
@@ -0,0 +1,105 @@
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class GroupRemind(db.Model):
|
||||
__tablename__ = "group_reminds"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
hy = db.Column(db.Boolean(), default=False) # 进群欢迎
|
||||
kxcz = db.Column(db.Boolean(), default=False) # 开箱重置
|
||||
zwa = db.Column(db.Boolean(), default=False) # 早晚安
|
||||
gb = db.Column(db.Boolean(), default=True) # 广播
|
||||
blpar = db.Column(db.Boolean(), default=True) # bilibili转发解析
|
||||
pa = db.Column(db.Boolean(), default=True) # 爬
|
||||
epic = db.Column(db.Boolean(), default=False) # epic
|
||||
almanac = db.Column(db.Boolean(), default=False) # 原神黄历
|
||||
|
||||
_idx1 = db.Index("info_group_reminds_idx1", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_status(cls, group_id: int, name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取群通知状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param name: 目标名称
|
||||
"""
|
||||
group = await cls.query.where((cls.group_id == group_id)).gino.first()
|
||||
if not group:
|
||||
group = await cls.create(
|
||||
group_id=group_id,
|
||||
)
|
||||
if name == "hy":
|
||||
return group.hy
|
||||
if name == "kxcz":
|
||||
return group.kxcz
|
||||
if name == "zwa":
|
||||
return group.zwa
|
||||
if name == "gb":
|
||||
return group.gb
|
||||
if name == "blpar":
|
||||
return group.blpar
|
||||
if name == "epic":
|
||||
return group.epic
|
||||
if name == "pa":
|
||||
return group.pa
|
||||
if name == "almanac":
|
||||
return group.almanac
|
||||
|
||||
@classmethod
|
||||
async def set_status(cls, group_id: int, name: str, status: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置群通知状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param name: 目标名称
|
||||
:param status: 通知状态
|
||||
"""
|
||||
try:
|
||||
group = (
|
||||
await cls.query.where((cls.group_id == group_id))
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not group:
|
||||
group = await cls.create(
|
||||
group_id=group_id,
|
||||
)
|
||||
if name == "hy":
|
||||
await group.update(
|
||||
hy=status,
|
||||
).apply()
|
||||
if name == "kxcz":
|
||||
await group.update(
|
||||
kxcz=status,
|
||||
).apply()
|
||||
if name == "zwa":
|
||||
await group.update(
|
||||
zwa=status,
|
||||
).apply()
|
||||
if name == "gb":
|
||||
await group.update(
|
||||
gb=status,
|
||||
).apply()
|
||||
if name == "blpar":
|
||||
await group.update(
|
||||
blpar=status,
|
||||
).apply()
|
||||
if name == "epic":
|
||||
await group.update(
|
||||
epic=status,
|
||||
).apply()
|
||||
if name == "pa":
|
||||
await group.update(
|
||||
pa=status,
|
||||
).apply()
|
||||
if name == "almanac":
|
||||
await group.update(
|
||||
almanac=status,
|
||||
).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
@@ -0,0 +1,124 @@
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class LevelUser(db.Model):
|
||||
__tablename__ = "level_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
user_level = db.Column(db.BigInteger(), nullable=False)
|
||||
group_flag = db.Column(db.Integer(), nullable=False, default=0)
|
||||
|
||||
_idx1 = db.Index("level_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取用户在群内的等级
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.user_level
|
||||
else:
|
||||
return -1
|
||||
|
||||
@classmethod
|
||||
async def set_level(
|
||||
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置用户在群内的权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
:param group_flag: 是否被自动更新刷新权限 0:是,1:否
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
user_level=level,
|
||||
group_flag=group_flag,
|
||||
)
|
||||
return True
|
||||
else:
|
||||
await user.update(user_level=level, group_flag=group_flag).apply()
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除用户权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
else:
|
||||
await user.delete()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检查用户权限等级是否大于 level
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
"""
|
||||
if group_id != 0:
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
user_level = user.user_level
|
||||
else:
|
||||
query = cls.query.where(cls.user_qq == user_qq)
|
||||
highest_level = 0
|
||||
for user in await query.gino.all():
|
||||
if user.user_level > highest_level:
|
||||
highest_level = user.user_level
|
||||
user_level = highest_level
|
||||
if user_level >= level:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测是否会被自动更新刷新权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
user = await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
).gino.first()
|
||||
if not user:
|
||||
return False
|
||||
if user.group_flag == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -0,0 +1,59 @@
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class OpenCasesUser(db.Model):
|
||||
__tablename__ = 'open_cases_users'
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
total_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
blue_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
blue_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
purple_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
purple_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
pink_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
pink_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
red_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
red_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
knife_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
knife_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
spend_money = db.Column(db.Integer(), nullable=False, default=0)
|
||||
make_money = db.Column(db.Float(), nullable=False, default=0)
|
||||
today_open_total = db.Column(db.Integer(), nullable=False, default=0)
|
||||
open_cases_time_last = db.Column(db.DateTime(timezone=True), nullable=False, default=datetime.now())
|
||||
knifes_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||
|
||||
_idx1 = db.Index('open_cases_group_users_idx1', 'user_qq', 'belonging_group', unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, belonging_group: int, for_update: bool = False) -> 'OpenCasesUser':
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
if for_update:
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
return user or await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_all(cls, group_id: int = None) -> 'list':
|
||||
user_list = []
|
||||
if not group_id:
|
||||
query = await cls.query.gino.all()
|
||||
else:
|
||||
query = await cls.query.where(
|
||||
(cls.belonging_group == group_id)
|
||||
).gino.all()
|
||||
for user in query:
|
||||
user_list.append(user)
|
||||
return user_list
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
from typing import Optional, List
|
||||
from services.db_context import db
|
||||
import asyncio
|
||||
|
||||
|
||||
class Pixiv(db.Model):
|
||||
__tablename__ = "pixiv"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
pid = db.Column(db.BigInteger(), nullable=False)
|
||||
title = db.Column(db.String(), nullable=False)
|
||||
width = db.Column(db.Integer(), nullable=False)
|
||||
height = db.Column(db.Integer(), nullable=False)
|
||||
view = db.Column(db.Integer(), nullable=False)
|
||||
bookmarks = db.Column(db.Integer(), nullable=False)
|
||||
img_url = db.Column(db.String(), nullable=False)
|
||||
img_p = db.Column(db.String(), nullable=False)
|
||||
uid = db.Column(db.BigInteger(), nullable=False)
|
||||
author = db.Column(db.String(), nullable=False)
|
||||
is_r18 = db.Column(db.Boolean(), nullable=False)
|
||||
tags = db.Column(db.String(), nullable=False)
|
||||
|
||||
_idx1 = db.Index("pixiv_idx1", "pid", "img_url", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_image_data(
|
||||
cls,
|
||||
pid: int,
|
||||
title: str,
|
||||
width: int,
|
||||
height: int,
|
||||
view: int,
|
||||
bookmarks: int,
|
||||
img_url: str,
|
||||
img_p: str,
|
||||
uid: int,
|
||||
author: str,
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加图片信息
|
||||
参数:
|
||||
:param pid: pid
|
||||
:param title: 标题
|
||||
:param width: 宽度
|
||||
:param height: 长度
|
||||
:param view: 被查看次数
|
||||
:param bookmarks: 收藏数
|
||||
:param img_url: url链接
|
||||
:param img_p: 张数
|
||||
:param uid: 作者uid
|
||||
:param author: 作者名称
|
||||
:param tags: 相关tag
|
||||
"""
|
||||
if not await cls.check_exists(pid, img_p):
|
||||
await cls.create(
|
||||
pid=pid,
|
||||
title=title,
|
||||
width=width,
|
||||
height=height,
|
||||
view=view,
|
||||
bookmarks=bookmarks,
|
||||
img_url=img_url,
|
||||
img_p=img_p,
|
||||
uid=uid,
|
||||
author=author,
|
||||
is_r18=True if 'R-18' in tags else False,
|
||||
tags=tags,
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除图片数据
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_p: 图片pid的张数,如:p0,p1
|
||||
"""
|
||||
try:
|
||||
if img_p:
|
||||
await cls.delete.where(
|
||||
(cls.pid == pid) & (cls.img_p == img_p)
|
||||
).gino.status()
|
||||
else:
|
||||
await cls.delete.where(cls.pid == pid).gino.status()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_pid(cls) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取所有PID
|
||||
"""
|
||||
pid = []
|
||||
query = await cls.query.gino.all()
|
||||
for image in query:
|
||||
if image.pid not in pid:
|
||||
pid.append(image.pid)
|
||||
return pid
|
||||
|
||||
# 0:非r18 1:r18 2:混合
|
||||
@classmethod
|
||||
async def query_images(
|
||||
cls,
|
||||
keyword: Optional[List[str]] = None,
|
||||
uid: Optional[int] = None,
|
||||
pid: Optional[int] = None,
|
||||
r18: int = 0,
|
||||
) -> List[Optional["Pixiv"]]:
|
||||
"""
|
||||
说明:
|
||||
查找符合条件的图片
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
:param uid: 画师uid
|
||||
:param pid: 图片pid
|
||||
:param r18: 是否r18,0:非r18 1:r18 2:混合
|
||||
"""
|
||||
if r18 == 0:
|
||||
query = await cls.query.where(cls.is_r18 == False).gino.all()
|
||||
elif r18 == 1:
|
||||
query = await cls.query.where(cls.is_r18 == True).gino.all()
|
||||
else:
|
||||
query = await cls.query.gino.all()
|
||||
if keyword:
|
||||
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
|
||||
elif uid:
|
||||
query = [x for x in query if x.uid == uid]
|
||||
elif pid:
|
||||
query = [x for x in query if x.pid == pid]
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def check_exists(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测pid是否已存在
|
||||
参数:
|
||||
:param pid: 图片PID
|
||||
:param img_p: 张数
|
||||
"""
|
||||
query = await cls.query.where(
|
||||
(cls.pid == pid) & (cls.img_p == img_p)
|
||||
).gino.all()
|
||||
return bool(query)
|
||||
|
||||
@classmethod
|
||||
async def get_keyword_num(cls, keyword: List[str]) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
获取相关关键词(keyword, tag)在图库中的数量
|
||||
参数:
|
||||
:param keyword: 关键词/Tag
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
i = int(len(query) / 200)
|
||||
mod = len(query) % 200
|
||||
tasks = []
|
||||
start = 0
|
||||
end = 200
|
||||
count = 0
|
||||
r18_count = 0
|
||||
for _ in range(i):
|
||||
tasks.append(asyncio.ensure_future(split_query_list(query[start: end], keyword)))
|
||||
start += 200
|
||||
end += 200
|
||||
if mod:
|
||||
tasks.append(asyncio.ensure_future(split_query_list(query[end:], keyword)))
|
||||
result = await asyncio.gather(*tasks)
|
||||
for x, j in result:
|
||||
count += x
|
||||
r18_count += j
|
||||
# query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
|
||||
# r18_count = len([x for x in query if x.is_r18])
|
||||
return count, r18_count
|
||||
|
||||
|
||||
async def split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _split_query_list, query, keyword)
|
||||
|
||||
|
||||
def _split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
|
||||
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
|
||||
r18_count = len([x for x in query if x.is_r18])
|
||||
return len(query) - r18_count, r18_count
|
||||
@@ -0,0 +1,126 @@
|
||||
from services.db_context import db
|
||||
from typing import Set, List
|
||||
|
||||
|
||||
class PixivKeywordUser(db.Model):
|
||||
__tablename__ = "pixiv_keyword_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
keyword = db.Column(db.String(), nullable=False)
|
||||
is_pass = db.Column(db.Boolean(), default=False)
|
||||
|
||||
_idx1 = db.Index("pixiv_keyword_users_idx1", "keyword", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_keyword(
|
||||
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加搜图的关键词
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param keyword: 关键词
|
||||
:param superusers: 是否为超级用户
|
||||
"""
|
||||
is_pass = True if str(user_qq) in superusers else False
|
||||
if not await cls._check_keyword_exists(keyword):
|
||||
await cls.create(
|
||||
user_qq=user_qq, group_id=group_id, keyword=keyword, is_pass=is_pass
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_keyword(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除关键词
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
if await cls._check_keyword_exists(keyword):
|
||||
query = cls.query.where(cls.keyword == keyword).with_for_update()
|
||||
query = await query.gino.first()
|
||||
await query.delete()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
通过或禁用关键词
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
:param is_pass: 通过状态
|
||||
"""
|
||||
if await cls._check_keyword_exists(keyword):
|
||||
query = cls.query.where(cls.keyword == keyword).with_for_update()
|
||||
query = await query.gino.first()
|
||||
await query.update(
|
||||
is_pass=is_pass,
|
||||
).apply()
|
||||
return query.user_qq, query.group_id
|
||||
return 0, 0
|
||||
|
||||
@classmethod
|
||||
async def get_all_user_dict(cls) -> dict:
|
||||
"""
|
||||
说明:
|
||||
获取关键词数据库各个用户贡献的关键词字典
|
||||
"""
|
||||
tmp = {}
|
||||
query = await cls.query.gino.all()
|
||||
for user in query:
|
||||
if not tmp.get(user.user_qq):
|
||||
tmp[user.user_qq] = {"keyword": []}
|
||||
tmp[user.user_qq]["keyword"].append(user.keyword)
|
||||
return tmp
|
||||
|
||||
@classmethod
|
||||
async def get_current_keyword(cls) -> "List[str], List[str]":
|
||||
"""
|
||||
说明:
|
||||
获取当前通过与未通过的关键词
|
||||
"""
|
||||
pass_keyword = []
|
||||
not_pass_keyword = []
|
||||
query = await cls.query.gino.all()
|
||||
for user in query:
|
||||
if user.is_pass:
|
||||
pass_keyword.append(user.keyword)
|
||||
else:
|
||||
not_pass_keyword.append(user.keyword)
|
||||
return pass_keyword, not_pass_keyword
|
||||
|
||||
@classmethod
|
||||
async def get_black_pid(cls) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取黑名单PID
|
||||
"""
|
||||
black_pid = []
|
||||
query = await cls.query.where(cls.user_qq == 114514).gino.all()
|
||||
for image in query:
|
||||
black_pid.append(image.keyword[6:])
|
||||
return black_pid
|
||||
|
||||
@classmethod
|
||||
async def _check_keyword_exists(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测关键词是否已存在
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
current_keyword = []
|
||||
query = await cls.query.gino.all()
|
||||
for user in query:
|
||||
current_keyword.append(user.keyword)
|
||||
if keyword in current_keyword:
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,73 @@
|
||||
from services.db_context import db
|
||||
from typing import List
|
||||
|
||||
|
||||
class RedbagUser(db.Model):
|
||||
__tablename__ = "redbag_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
send_redbag_count = db.Column(db.Integer(), default=0)
|
||||
get_redbag_count = db.Column(db.Integer(), default=0)
|
||||
spend_gold = db.Column(db.Integer(), default=0)
|
||||
get_gold = db.Column(db.Integer(), default=0)
|
||||
|
||||
_idx1 = db.Index("redbag_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
|
||||
"""
|
||||
说明:
|
||||
添加收发红包数据
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 收或发
|
||||
:param money: 金钱数量
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.with_for_update().gino.first() or await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
)
|
||||
if itype == "get":
|
||||
await user.update(
|
||||
get_redbag_count=user.get_redbag_count + 1,
|
||||
get_gold=user.get_gold + money,
|
||||
).apply()
|
||||
else:
|
||||
await user.update(
|
||||
send_redbag_count=user.send_redbag_count + 1,
|
||||
spend_gold=user.spend_gold + money,
|
||||
).apply()
|
||||
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first() or await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
)
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有用户对象
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
query = await cls.query.gino.all()
|
||||
else:
|
||||
query = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||
return query
|
||||
@@ -0,0 +1,108 @@
|
||||
from services.db_context import db
|
||||
from typing import List
|
||||
|
||||
|
||||
class RussianUser(db.Model):
|
||||
__tablename__ = "russian_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
win_count = db.Column(db.Integer(), default=0)
|
||||
fail_count = db.Column(db.Integer(), default=0)
|
||||
make_money = db.Column(db.Integer(), default=0)
|
||||
lose_money = db.Column(db.Integer(), default=0)
|
||||
|
||||
_idx1 = db.Index("russian_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
|
||||
"""
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
user = (
|
||||
await cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
return user or await cls.create(user_qq=user_qq, group_id=group_id)
|
||||
|
||||
@classmethod
|
||||
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加用户输赢次数
|
||||
说明:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
"""
|
||||
try:
|
||||
user = (
|
||||
await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not user:
|
||||
user = await cls.create(user_qq=user_qq, group_id=group_id)
|
||||
if itype == "win":
|
||||
await user.update(
|
||||
win_count=user.win_count + 1,
|
||||
).apply()
|
||||
elif itype == "lose":
|
||||
await user.update(
|
||||
fail_count=user.fail_count + 1,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加用户输赢金钱
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
:param count: 金钱数量
|
||||
"""
|
||||
try:
|
||||
user = (
|
||||
await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not user:
|
||||
user = await cls.create(user_qq=user_qq, group_id=group_id)
|
||||
if itype == "win":
|
||||
await user.update(
|
||||
make_money=user.make_money + count,
|
||||
).apply()
|
||||
elif itype == "lose":
|
||||
await user.update(
|
||||
lose_money=user.lose_money + count,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_user(cls, group_id: int) -> List["RussianUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户对象
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
users = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||
return users
|
||||
@@ -0,0 +1,168 @@
|
||||
from services.db_context import db
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class Setu(db.Model):
|
||||
__tablename__ = "setu"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
local_id = db.Column(db.Integer(), nullable=False)
|
||||
title = db.Column(db.String(), nullable=False)
|
||||
author = db.Column(db.String(), nullable=False)
|
||||
pid = db.Column(db.BigInteger(), nullable=False)
|
||||
img_hash = db.Column(db.String(), nullable=False)
|
||||
img_url = db.Column(db.String(), nullable=False)
|
||||
is_r18 = db.Column(db.Boolean(), nullable=False)
|
||||
tags = db.Column(db.String())
|
||||
|
||||
_idx1 = db.Index("setu_pid_img_url_idx1", "pid", "img_url", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_setu_data(
|
||||
cls,
|
||||
local_id: int,
|
||||
title: str,
|
||||
author: str,
|
||||
pid: int,
|
||||
img_hash: str,
|
||||
img_url: str,
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加一份色图数据
|
||||
参数:
|
||||
:param local_id: 本地存储id
|
||||
:param title: 标题
|
||||
:param author: 作者
|
||||
:param pid: 图片pid
|
||||
:param img_hash: 图片hash值
|
||||
:param img_url: 图片链接
|
||||
:param tags: 图片标签
|
||||
"""
|
||||
if not await cls._check_exists(pid, img_url):
|
||||
await cls.create(
|
||||
local_id=local_id,
|
||||
title=title,
|
||||
author=author,
|
||||
pid=pid,
|
||||
img_hash=img_hash,
|
||||
img_url=img_url,
|
||||
is_r18=True if "R-18" in tags else False,
|
||||
tags=tags,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def query_image(
|
||||
cls,
|
||||
local_id: Optional[int] = None,
|
||||
tags: Optional[List[str]] = None,
|
||||
r18: int = 0,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
通过tag查找色图
|
||||
参数:
|
||||
:param local_id: 本地色图 id
|
||||
:param tags: tags
|
||||
:param r18: 是否 r18,0:非r18 1:r18 2:混合
|
||||
"""
|
||||
if local_id:
|
||||
flag = True if r18 == 1 else False
|
||||
return await cls.query.where(
|
||||
(cls.local_id == local_id) & (cls.is_r18 == flag)
|
||||
).gino.first()
|
||||
if r18 == 0:
|
||||
query = await cls.query.where(cls.is_r18 == False).gino.all()
|
||||
elif r18 == 1:
|
||||
query = await cls.query.where(cls.is_r18 == True).gino.all()
|
||||
else:
|
||||
query = await cls.query.gino.all()
|
||||
if tags:
|
||||
query = [x for x in query if set(x.tags.split(",")) > set(tags)]
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_image_count(cls, r18: int = 0):
|
||||
"""
|
||||
说明:
|
||||
查询图片数量
|
||||
"""
|
||||
return len(await cls.query_image(r18=r18))
|
||||
# return await db.func.count(cls.local_id).gino.scalar()
|
||||
|
||||
@classmethod
|
||||
async def get_image_in_hash(cls, img_hash: str) -> "Setu":
|
||||
"""
|
||||
说明:
|
||||
通过图像hash获取图像信息
|
||||
参数:
|
||||
:param img_hash: = 图像hash值
|
||||
"""
|
||||
query = await cls.query.where(cls.img_hash == img_hash).gino.first()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def _check_exists(cls, pid: int, img_url: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测图片是否存在
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_url: 图片链接
|
||||
"""
|
||||
return bool(
|
||||
await cls.query.where(
|
||||
(cls.pid == pid) & (cls.img_url == img_url)
|
||||
).gino.first()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def update_setu_data(
|
||||
cls,
|
||||
pid: int,
|
||||
*,
|
||||
local_id: Optional[int] = None,
|
||||
title: Optional[str] = None,
|
||||
author: Optional[str] = None,
|
||||
img_hash: Optional[str] = None,
|
||||
img_url: Optional[str] = None,
|
||||
tags: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
根据PID修改图片数据
|
||||
参数:
|
||||
:param local_id: 本地id
|
||||
:param pid: 图片pid
|
||||
:param title: 标题
|
||||
:param author: 作者
|
||||
:param img_hash: 图片hash值
|
||||
:param img_url: 图片链接
|
||||
:param tags: 图片标签
|
||||
"""
|
||||
query = cls.query.where(cls.pid == pid).with_for_update()
|
||||
image_list = await query.gino.all()
|
||||
if image_list:
|
||||
for image in image_list:
|
||||
if local_id:
|
||||
await image.update(local_id=local_id).apply()
|
||||
if title:
|
||||
await image.update(title=title).apply()
|
||||
if author:
|
||||
await image.update(author=author).apply()
|
||||
if img_hash:
|
||||
await image.update(img_hash=img_hash).apply()
|
||||
if img_url:
|
||||
await image.update(img_url=img_url).apply()
|
||||
if tags:
|
||||
await image.update(tags=tags).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_setu(cls) -> List["Setu"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有图片对象
|
||||
"""
|
||||
return await cls.query.gino.all()
|
||||
@@ -0,0 +1,62 @@
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class SignGroupUser(db.Model):
|
||||
__tablename__ = "sign_group_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
|
||||
checkin_count = db.Column(db.Integer(), nullable=False)
|
||||
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
|
||||
add_probability = db.Column(
|
||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||
)
|
||||
specify_probability = db.Column(
|
||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||
)
|
||||
|
||||
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(
|
||||
cls, user_qq: int, belonging_group: int, for_update: bool = False
|
||||
) -> "SignGroupUser":
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
if for_update:
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
return user or await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
checkin_count=0,
|
||||
checkin_time_last=datetime.min, # 从未签到过
|
||||
impression=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_all_impression(cls, belonging_group: int) -> "list, list":
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户 id 及对应 好感度
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
impression_list = []
|
||||
user_qq_list = []
|
||||
user_group = []
|
||||
if belonging_group:
|
||||
query = cls.query.where(cls.belonging_group == belonging_group)
|
||||
else:
|
||||
query = cls.query
|
||||
for user in await query.gino.all():
|
||||
impression_list.append(user.impression)
|
||||
user_qq_list.append(user.user_qq)
|
||||
user_group.append(user.belonging_group)
|
||||
return user_qq_list, impression_list, user_group
|
||||
@@ -0,0 +1,58 @@
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from nonebot import on_command
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from utils.utils import FreqLimiter
|
||||
|
||||
|
||||
__plugin_name__ = "基本设置 [Hidden]"
|
||||
__plugin_usage__ = "用法: 无"
|
||||
|
||||
|
||||
_flmt = FreqLimiter(300)
|
||||
|
||||
|
||||
config_playgame = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True)
|
||||
|
||||
|
||||
@config_playgame.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if not _flmt.check(event.group_id):
|
||||
return
|
||||
_flmt.start_cd(event.group_id)
|
||||
await config_playgame.finish(
|
||||
image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi")
|
||||
)
|
||||
|
||||
|
||||
self_introduction = on_command(
|
||||
"自我介绍", aliases={"介绍", "你是谁", "你叫什么"}, rule=to_me(), priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@self_introduction.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
result = (
|
||||
"我叫绪山真寻\n"
|
||||
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
|
||||
"年龄的话我还是个**岁初中生(至少现在是)\n"
|
||||
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
|
||||
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
|
||||
"最好的朋友是椛!\n" + image("zhenxun")
|
||||
)
|
||||
await self_introduction.finish(result)
|
||||
|
||||
|
||||
my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@my_wife.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await my_wife.finish(image("laopo.jpg", "other"))
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from nonebot.plugin import export
|
||||
from .data_source import update_member_info
|
||||
from .custom_welcome_message import *
|
||||
from .group_notification_state import *
|
||||
from .switch_rule import *
|
||||
from .update_group_member_info import *
|
||||
from .timing_task import *
|
||||
|
||||
|
||||
export = export()
|
||||
export.update_member_info = update_member_info
|
||||
@@ -0,0 +1,37 @@
|
||||
from nonebot import on_command
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import custom_group_welcome
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__plugin_name__ = "自定义进群欢迎消息"
|
||||
|
||||
__plugin_usage__ = """
|
||||
自定义进群欢迎消息 [消息] [图片](可省略)
|
||||
示例:自定义进群欢迎消息 欢迎新人![图片]
|
||||
"""
|
||||
|
||||
|
||||
custom_welcome = on_command(
|
||||
"自定义进群欢迎消息",
|
||||
aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"},
|
||||
permission=GROUP,
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
|
||||
|
||||
@custom_welcome.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
if not msg and not imgs:
|
||||
await custom_welcome.finish(__plugin_usage__)
|
||||
await custom_welcome.send(
|
||||
await custom_group_welcome(msg, imgs, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
|
||||
@@ -0,0 +1,210 @@
|
||||
from models.group_remind import GroupRemind
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
import os
|
||||
import aiofiles
|
||||
import aiohttp
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_local_proxy, get_bot
|
||||
from pathlib import Path
|
||||
from nonebot import require
|
||||
from configs.config import plugins2info_dict
|
||||
from models.group_member_info import GroupInfoUser
|
||||
import time
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import ADMIN_DEFAULT_AUTH
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
export = require("nonebot_plugin_manager")
|
||||
|
||||
|
||||
command_dict = {
|
||||
'早晚安': 'zwa',
|
||||
'进群欢迎': 'hy',
|
||||
'每日开箱重置提醒': 'kxcz',
|
||||
'b站转发解析': 'blpar',
|
||||
'epic': 'epic',
|
||||
'丢人爬': 'pa',
|
||||
'原神黄历提醒': 'almanac',
|
||||
}
|
||||
command_list = list(command_dict.values())
|
||||
command_info_dt = {
|
||||
'早晚安': '将会在每晚11:59晚安,在6:01早安哦',
|
||||
'每日开箱重置提醒': '将会在每日00:01提示开箱重置!',
|
||||
'epic': '将会在每日中午12:01发送可白嫖的epic游戏',
|
||||
'原神黄历提醒': '将会在每日8:00发送当日的原神黄历',
|
||||
}
|
||||
|
||||
|
||||
async def remind_status(group: int, name: str, flag: bool) -> str:
|
||||
_name = ''
|
||||
if name in command_dict.values():
|
||||
_name = list(command_dict.keys())[list(command_dict.values()).index(name)]
|
||||
if flag:
|
||||
rst = '开启'
|
||||
if await GroupRemind.get_status(group, name):
|
||||
return f'该群已经{rst}过 {_name},请勿重复开启!'
|
||||
else:
|
||||
rst = '关闭'
|
||||
if not await GroupRemind.get_status(group, name):
|
||||
return f'该群已经{rst}过 {_name},请勿重复开启!'
|
||||
if await GroupRemind.set_status(group, name, flag):
|
||||
info = command_info_dt[_name] if command_info_dt.get(_name) else ''
|
||||
if info:
|
||||
info = '\n' + info
|
||||
return f'成功{rst} {_name}!0v0 {info}'
|
||||
else:
|
||||
return f'{rst} {_name} 失败了...'
|
||||
|
||||
|
||||
async def set_group_status(name: str, group_id: int):
|
||||
flag = None
|
||||
if name[:2] == '开启':
|
||||
flag = True
|
||||
elif name[:2] == '关闭':
|
||||
flag = False
|
||||
cmd = name[2:]
|
||||
if cmd in ['全部通知', '所有通知']:
|
||||
for command in command_list:
|
||||
await remind_status(group_id, command, flag)
|
||||
return f'已{name[:2]}所有通知!'
|
||||
return await remind_status(group_id, command_dict[cmd], flag)
|
||||
|
||||
|
||||
async def group_current_status(group_id: int):
|
||||
result = f'(被动技能)\n早晚安通知:{"√" if await GroupRemind.get_status(group_id, "zwa") else "×"}\n' \
|
||||
f'进群欢迎:{"√" if await GroupRemind.get_status(group_id, "hy") else "×"}\n' \
|
||||
f'每日开箱重置通知:{"√" if await GroupRemind.get_status(group_id, "kxcz") else "×"}\n' \
|
||||
f'b站转发解析:{"√" if await GroupRemind.get_status(group_id, "blpar") else "×"}\n' \
|
||||
f'丢人爬:{"√" if await GroupRemind.get_status(group_id, "pa") else "×"}\n' \
|
||||
f'epic免费游戏:{"√" if await GroupRemind.get_status(group_id, "epic") else "×"}\n' \
|
||||
f'原神黄历提醒:{"√" if await GroupRemind.get_status(group_id, "almanac") else "×"}'
|
||||
return result
|
||||
|
||||
|
||||
custom_welcome_msg_json = Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
|
||||
|
||||
async def custom_group_welcome(msg, imgs, user_id, group_id):
|
||||
img_result = ''
|
||||
img = imgs[0] if imgs else ''
|
||||
result = ''
|
||||
if os.path.exists(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg'):
|
||||
os.remove(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg')
|
||||
# print(custom_welcome_msg_json)
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, 'r'))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(data, open(custom_welcome_msg_json, 'w'), indent=4, ensure_ascii=False)
|
||||
logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}')
|
||||
result += msg
|
||||
if img:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(img, proxy=get_local_proxy()) as response:
|
||||
async with aiofiles.open(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg', 'wb') as f:
|
||||
await f.write(await response.read())
|
||||
img_result = image(abspath=DATA_PATH + f'custom_welcome_msg/{group_id}.jpg')
|
||||
logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息图片')
|
||||
except Exception as e:
|
||||
logger.error(f'GROUP {group_id} 替换群消息失败 e:{e}')
|
||||
return '替换群消息失败..'
|
||||
return f'替换群欢迎消息成功:\n{result}' + img_result
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int):
|
||||
group_id = str(group_id)
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
try:
|
||||
with open(DATA_PATH + 'manager/plugin_list.json', 'r', encoding='utf8') as f:
|
||||
plugin_list = json.load(f)
|
||||
except ValueError:
|
||||
pass
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
for plugin_cmd in plugins2info_dict.keys():
|
||||
if cmd in plugins2info_dict[plugin_cmd]['cmd']:
|
||||
# print(plugin_list[plugin_cmd])
|
||||
if status == '开启':
|
||||
# if group_id in plugin_list[plugin_cmd]:
|
||||
if group_id not in plugin_list[plugin_cmd] or plugin_list[plugin_cmd][group_id]:
|
||||
return f'功能 {cmd} 正处于开启状态!不要重复开启.'
|
||||
export.unblock_plugin(group_id, plugin_cmd)
|
||||
else:
|
||||
if group_id in plugin_list[plugin_cmd]:
|
||||
if not plugin_list[plugin_cmd][group_id]:
|
||||
return f'功能 {cmd} 正处于关闭状态!不要重复关闭.'
|
||||
export.block_plugin(group_id, plugin_cmd)
|
||||
if os.path.exists(DATA_PATH + f'group_help/{group_id}.png'):
|
||||
os.remove(DATA_PATH + f'group_help/{group_id}.png')
|
||||
|
||||
return f'{status} {cmd} 功能!'
|
||||
return f'没有找到 {cmd} 功能喔'
|
||||
|
||||
|
||||
async def update_member_info(group_id: int) -> bool:
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info['card'] == "":
|
||||
nickname = user_info['nickname']
|
||||
else:
|
||||
nickname = user_info['card']
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if user_info['role'] in ['owner', 'admin'] and not await LevelUser.is_group_flag(user_info['user_id'], group_id):
|
||||
await LevelUser.set_level(user_info['user_id'], user_info['group_id'], ADMIN_DEFAULT_AUTH)
|
||||
if str(user_info['user_id']) in bot.config.superusers:
|
||||
await LevelUser.set_level(user_info['user_id'], user_info['group_id'], 9)
|
||||
user = await GroupInfoUser.get_member_info(user_info['user_id'], user_info['group_id'])
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功")
|
||||
_exist_member_list.append(int(user_info['user_id']))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user_info['join_time'])), "%Y-%m-%d %H:%M:%S")
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info['user_id'],
|
||||
user_info['group_id'],
|
||||
nickname,
|
||||
join_time,):
|
||||
_exist_member_list.append(int(user_info['user_id']))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n")
|
||||
_del_member_list = list(set(_exist_member_list).difference(set(await GroupInfoUser.get_group_member_id_list(group_id))))
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(user_id=int(list(bot.config.superusers)[0]), message=result[:-1])
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import set_group_status, group_current_status
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.log import logger
|
||||
from nonebot import on_command
|
||||
|
||||
|
||||
__plugin_name__ = "群通知开关"
|
||||
|
||||
__plugin_usage__ = """
|
||||
示例:
|
||||
开启早晚安
|
||||
关闭早晚安
|
||||
"""
|
||||
|
||||
|
||||
group_status = on_command(
|
||||
"oc_reminds",
|
||||
aliases={
|
||||
"开启早晚安",
|
||||
"关闭早晚安",
|
||||
"开启进群欢迎",
|
||||
"关闭进群欢迎",
|
||||
"开启每日开箱重置提醒",
|
||||
"关闭每日开箱重置提醒",
|
||||
"开启b站转发解析",
|
||||
"关闭b站转发解析",
|
||||
"开启epic通知",
|
||||
"关闭epic通知",
|
||||
"开启丢人爬",
|
||||
"关闭丢人爬",
|
||||
"开启原神黄历提醒",
|
||||
"关闭原神黄历提醒",
|
||||
"开启全部通知",
|
||||
"开启所有通知",
|
||||
"关闭全部通知",
|
||||
"关闭所有通知",
|
||||
"群通知状态",
|
||||
},
|
||||
permission=GROUP,
|
||||
priority=1,
|
||||
block=True,
|
||||
)
|
||||
|
||||
|
||||
@group_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if state["_prefix"]["raw_command"] in ["群通知状态"]:
|
||||
await group_status.finish(await group_current_status(event.group_id))
|
||||
await group_status.send(
|
||||
await set_group_status(state["_prefix"]["raw_command"], event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f'USER {event.user_id} GROUP {event.group_id} 使用群通知管理命令 {state["_prefix"]["raw_command"]}'
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import change_group_switch
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.log import logger
|
||||
from configs.config import plugins2info_dict
|
||||
|
||||
|
||||
__plugin_name__ = "群功能开关"
|
||||
|
||||
__plugin_usage__ = """
|
||||
示例:
|
||||
开启色图
|
||||
关闭色图
|
||||
"""
|
||||
|
||||
|
||||
cmds = []
|
||||
for cmd_list in plugins2info_dict.values():
|
||||
for cmd in cmd_list["cmd"]:
|
||||
cmds.append(f"开启{cmd}")
|
||||
cmds.append(f"关闭{cmd}")
|
||||
cmds = set(cmds)
|
||||
|
||||
|
||||
switch_rule = on_command(
|
||||
"switch_rule", aliases=cmds, permission=GROUP, priority=4, block=True
|
||||
)
|
||||
|
||||
|
||||
@switch_rule.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await switch_rule.send(
|
||||
await change_group_switch(
|
||||
state["_prefix"]["raw_command"].strip(), event.group_id
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
f'USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {state["_prefix"]["raw_command"]}'
|
||||
)
|
||||
@@ -0,0 +1,42 @@
|
||||
from utils.utils import scheduler, get_bot
|
||||
from .data_source import update_member_info
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from asyncpg.exceptions import ConnectionDoesNotExistError
|
||||
|
||||
|
||||
# 自动更新群员信息
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=2,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list(self_id=bot.self_id)
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
try:
|
||||
await update_member_info(g)
|
||||
logger.info(f"更新群组 g:{g} 成功")
|
||||
except Exception as e:
|
||||
logger.error(f"更新群组错误 g:{g} e:{e}")
|
||||
|
||||
|
||||
# 快速更新群员信息以及管理员权限
|
||||
@scheduler.scheduled_job(
|
||||
"interval",
|
||||
minutes=5,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list(self_id=bot.self_id)
|
||||
gl = [g["group_id"] for g in gl]
|
||||
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
|
||||
for g in gl:
|
||||
if g not in all_group:
|
||||
await update_member_info(g)
|
||||
logger.info(f"快速更新群信息以及权限:{g}")
|
||||
except (IndexError, ConnectionDoesNotExistError):
|
||||
pass
|
||||
@@ -0,0 +1,27 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import update_member_info
|
||||
|
||||
__plugin_name__ = "更新群组成员列表"
|
||||
|
||||
__plugin_usage__ = """
|
||||
说明:
|
||||
更新群组成员的基本信息
|
||||
示例:
|
||||
更新群组成员列表
|
||||
"""
|
||||
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
refresh_member_group = on_command(
|
||||
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@refresh_member_group.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await update_member_info(event.group_id):
|
||||
await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
|
||||
else:
|
||||
await refresh_member_group.finish("更新群员信息失败!", at_sender=True)
|
||||
@@ -0,0 +1,31 @@
|
||||
from nonebot import on_notice
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.level_user import LevelUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from configs.config import ADMIN_DEFAULT_AUTH
|
||||
|
||||
|
||||
__plugin_name__ = "群管理员监测"
|
||||
|
||||
__plugin_usage__ = "无"
|
||||
|
||||
|
||||
admin_notice = on_notice(priority=5)
|
||||
|
||||
|
||||
@admin_notice.handle()
|
||||
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
|
||||
try:
|
||||
nickname = (
|
||||
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
|
||||
).user_name
|
||||
except AttributeError:
|
||||
nickname = event.user_id
|
||||
if event.sub_type == "set":
|
||||
await LevelUser.set_level(event.user_id, event.group_id, ADMIN_DEFAULT_AUTH)
|
||||
logger.info(f"为新晋管理员 {nickname}({event.user_id}) 添加权限等级:{ADMIN_DEFAULT_AUTH}")
|
||||
elif event.sub_type == "unset":
|
||||
await LevelUser.delete_level(event.user_id, event.group_id)
|
||||
logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
|
||||
@@ -0,0 +1,53 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent
|
||||
from utils.image_utils import CreateImg
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
|
||||
|
||||
__plugin_name__ = '管理帮助 [Hidden]'
|
||||
__plugin_usage__ = '''管理帮助(权限等级):
|
||||
1.更新群组成员列表(1)
|
||||
2.功能开关 --> 指令:开启/关闭xx功能(2)
|
||||
3.查看群被动技能 --> 指令:群通知状态(2)
|
||||
4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2)
|
||||
5.将用户拉入真寻黑名单 --> .ban/.unban(5)
|
||||
6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间
|
||||
\t\t/设置检测次数/设置禁言时长(5)
|
||||
7.群员活跃度相关 --> 指令:群员活跃检测设置
|
||||
设置群员活跃检测时长(天)
|
||||
添加群员活跃检测白名单[at]...
|
||||
查看群员活跃检测白名单(5)
|
||||
8.上传图片(6)
|
||||
9.移动图片(7)
|
||||
10.删除图片(7)
|
||||
对我说 “真寻帮助 指令” 获取对应详细帮助
|
||||
群主与管理员默认 5 级权限
|
||||
'''
|
||||
|
||||
passive_help = '''【被动技能开关(2):
|
||||
开启/关闭早晚安
|
||||
开启/关闭进群欢迎
|
||||
开启/关闭每日开箱重置提醒
|
||||
开启/关闭b站转发解析
|
||||
开启/关闭丢人爬
|
||||
开启/关闭epic通知
|
||||
开启/关闭原神黄历提醒
|
||||
开启/关闭全部通知】
|
||||
'''
|
||||
|
||||
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
|
||||
|
||||
admin_help_img = CreateImg(1000, 600, font_size=24)
|
||||
admin_help_img.text((10, 10), __plugin_usage__)
|
||||
text_img = CreateImg(450, 600, font_size=24)
|
||||
text_img.text((0, 0), passive_help)
|
||||
admin_help_img.paste(text_img, (650, 50))
|
||||
admin_help_img.save(IMAGE_PATH + 'admin_help_img.png')
|
||||
|
||||
|
||||
@admin_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await admin_help.send(image('admin_help_img.png'))
|
||||