nonebot-plugin-savepic 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/PKG-INFO +6 -2
- nonebot_plugin_savepic-0.2.0/nonebot_plugin_savepic/__init__.py +190 -0
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/config.py +2 -0
- nonebot_plugin_savepic-0.2.0/nonebot_plugin_savepic/ext_listener.py +34 -0
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/model.py +7 -1
- nonebot_plugin_savepic-0.2.0/nonebot_plugin_savepic/pic_sql.py +219 -0
- nonebot_plugin_savepic-0.2.0/nonebot_plugin_savepic/picture.py +48 -0
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/rule.py +2 -2
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/pyproject.toml +6 -2
- nonebot_plugin_savepic-0.1.2/nonebot_plugin_savepic/__init__.py +0 -154
- nonebot_plugin_savepic-0.1.2/nonebot_plugin_savepic/pic_sql.py +0 -150
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/LICENSE +0 -0
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/README.md +0 -0
- {nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/migrations/1a654e02179b_.py +0 -0
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nonebot-plugin-savepic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: 保存表情包(语录)与随机出图
|
|
5
5
|
Home-page: https://github.com/Yan-Zero/nonebot-plugin-savepic
|
|
6
6
|
License: MIT
|
|
7
7
|
Author: Yan
|
|
8
8
|
Author-email: 1964649083@qq.com
|
|
9
|
-
Requires-Python: >=3.10,<
|
|
9
|
+
Requires-Python: >=3.10,<3.13
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Requires-Dist: arclet-alconna (>=1.7.14,<2.0.0)
|
|
14
15
|
Requires-Dist: asyncpg (>=0.28.0,<0.29.0)
|
|
15
16
|
Requires-Dist: nonebot-adapter-onebot (>=2.2.3,<3.0.0)
|
|
16
17
|
Requires-Dist: nonebot-plugin-datastore (>=1.1.0,<2.0.0)
|
|
17
18
|
Requires-Dist: nonebot2 (>=2.0.1,<3.0.0)
|
|
19
|
+
Requires-Dist: numpy (>=1.25.2,<2.0.0)
|
|
20
|
+
Requires-Dist: pillow (>=10.0.0,<11.0.0)
|
|
21
|
+
Requires-Dist: scipy (>=1.11.1,<2.0.0)
|
|
18
22
|
Description-Content-Type: text/markdown
|
|
19
23
|
|
|
20
24
|
<div align="center">
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from nonebot import require
|
|
2
|
+
from nonebot import get_driver
|
|
3
|
+
from nonebot import on_command
|
|
4
|
+
from nonebot.params import CommandArg, Arg
|
|
5
|
+
from nonebot.adapters.onebot.v11.message import Message as V11Msg
|
|
6
|
+
from nonebot.adapters.onebot.v11.message import MessageSegment as V11Seg
|
|
7
|
+
from nonebot.internal.adapter.bot import Bot
|
|
8
|
+
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
|
|
9
|
+
from nonebot.matcher import Matcher
|
|
10
|
+
from nonebot.typing import T_State
|
|
11
|
+
from nonebot.plugin import PluginMetadata
|
|
12
|
+
from asyncpg.exceptions import InvalidRegularExpressionError
|
|
13
|
+
from arclet.alconna import Alconna, Option, Args, CommandMeta, append
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
require("nonebot_plugin_datastore")
|
|
17
|
+
|
|
18
|
+
from .config import Config
|
|
19
|
+
from .pic_sql import savepic, rename, delete, write_pic, randpic, load_pic, select_pic
|
|
20
|
+
from .rule import PIC_AMDIN
|
|
21
|
+
from .ext_listener import pic_listen
|
|
22
|
+
from .picture import p_hash
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__plugin_meta__ = PluginMetadata(
|
|
26
|
+
name="Savepic",
|
|
27
|
+
description="表情包保存",
|
|
28
|
+
usage="""用法:
|
|
29
|
+
/savepic <文件名> <图片>
|
|
30
|
+
/savepic -g <文件名> <全局图片>
|
|
31
|
+
/savepic -d <文件名> 删除图图片
|
|
32
|
+
/savepic -m <原文件名> <新文件名> 重命名图片
|
|
33
|
+
/randpic <关键词> 随机图片
|
|
34
|
+
<文件名> 发送图片""",
|
|
35
|
+
config=Config,
|
|
36
|
+
homepage="https://github.com/Yan-Zero/nonebot-plugin-savepic",
|
|
37
|
+
type="application",
|
|
38
|
+
supported_adapters=["~onebot.v11"],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
INVALID_FILENAME_CHARACTERS = r'\/:*?"<>|'
|
|
42
|
+
|
|
43
|
+
p_config = Config.parse_obj(get_driver().config)
|
|
44
|
+
|
|
45
|
+
rpic = on_command("randpic", aliases={"随机图"}, priority=5)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@rpic.handle()
|
|
49
|
+
async def _(bot: Bot, event, args: V11Msg = CommandArg()):
|
|
50
|
+
reg = args.extract_plain_text().strip()
|
|
51
|
+
group_id = (
|
|
52
|
+
"globe"
|
|
53
|
+
if not isinstance(event, GroupMessageEvent)
|
|
54
|
+
else f"qq_group:{event.group_id}"
|
|
55
|
+
)
|
|
56
|
+
try:
|
|
57
|
+
pic = await randpic(reg, group_id)
|
|
58
|
+
if pic:
|
|
59
|
+
file_ = await load_pic(pic.url)
|
|
60
|
+
await bot.send(event, V11Msg([pic.name + "\n", V11Seg.image(file=file_)]))
|
|
61
|
+
except InvalidRegularExpressionError:
|
|
62
|
+
await rpic.finish("正则表达式错误")
|
|
63
|
+
except Exception as ex:
|
|
64
|
+
await rpic.finish(str(ex))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
spic = on_command("savepic", aliases={"存图"}, priority=5)
|
|
68
|
+
a_spic = Alconna(
|
|
69
|
+
"/savepic",
|
|
70
|
+
Option("-d", help_text="删除图片"),
|
|
71
|
+
Option("-g", help_text="全局"),
|
|
72
|
+
Option("-ac", help_text="允许相似碰撞"),
|
|
73
|
+
Args.filename[str],
|
|
74
|
+
meta=CommandMeta(description="保存图片,默认保存到本群"),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@spic.handle()
|
|
79
|
+
async def _(
|
|
80
|
+
bot: Bot,
|
|
81
|
+
matcher: Matcher,
|
|
82
|
+
event: GroupMessageEvent,
|
|
83
|
+
state: T_State,
|
|
84
|
+
):
|
|
85
|
+
command = a_spic.parse(event.message.extract_plain_text())
|
|
86
|
+
if not command.matched:
|
|
87
|
+
await spic.finish(str(command.error_info) + "\n\n" + a_spic.get_help())
|
|
88
|
+
|
|
89
|
+
state["savepiv_group"] = "globe" if command.g else f"qq_group:{event.group_id}"
|
|
90
|
+
filename = command.filename
|
|
91
|
+
for c in INVALID_FILENAME_CHARACTERS:
|
|
92
|
+
filename = filename.replace(c, "-")
|
|
93
|
+
if not filename.endswith((".jpg", ".png", ".gif")):
|
|
94
|
+
filename += ".jpg"
|
|
95
|
+
state["savepiv_filename"] = filename
|
|
96
|
+
state["savepiv_ac"] = command.ac is not None
|
|
97
|
+
|
|
98
|
+
if command.d:
|
|
99
|
+
if not await PIC_AMDIN(bot, event):
|
|
100
|
+
await spic.finish("不支持选项 -d")
|
|
101
|
+
try:
|
|
102
|
+
await delete(filename, state["savepiv_group"])
|
|
103
|
+
except Exception as ex:
|
|
104
|
+
await spic.finish(str(ex))
|
|
105
|
+
await spic.finish("图片已删除")
|
|
106
|
+
|
|
107
|
+
pic = await select_pic(filename, state["savepiv_group"])
|
|
108
|
+
if pic and pic.group == state["savepiv_group"]:
|
|
109
|
+
spic.finish("文件名已存在。")
|
|
110
|
+
|
|
111
|
+
picture = event.message.get("image")
|
|
112
|
+
if not picture and event.reply:
|
|
113
|
+
picture = event.reply.message.get("image")
|
|
114
|
+
if picture:
|
|
115
|
+
matcher.set_arg("picture", picture)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@spic.got("picture", "图呢?")
|
|
119
|
+
async def _(state: T_State, picture: V11Msg = Arg()):
|
|
120
|
+
picture = picture.get("image")
|
|
121
|
+
if not picture:
|
|
122
|
+
await spic.finish("6,这也不是图啊")
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
dir = await write_pic(picture[0].data["url"], p_config.savepic_dir)
|
|
126
|
+
except Exception as ex:
|
|
127
|
+
await spic.finish("存图失败。" + "\n" + str(ex))
|
|
128
|
+
try:
|
|
129
|
+
await savepic(
|
|
130
|
+
state["savepiv_filename"],
|
|
131
|
+
dir,
|
|
132
|
+
p_hash(await load_pic(dir)),
|
|
133
|
+
state["savepiv_group"],
|
|
134
|
+
state["savepiv_ac"],
|
|
135
|
+
)
|
|
136
|
+
await spic.send("保存成功")
|
|
137
|
+
except Exception as ex:
|
|
138
|
+
os.remove(dir)
|
|
139
|
+
await spic.finish(str(ex))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
s_mvpic = on_command("mvpic", priority=5)
|
|
143
|
+
a_mvpic = Alconna(
|
|
144
|
+
"/mvpic",
|
|
145
|
+
Option("-l", args=Args.filename[str], help_text="本地图片", action=append),
|
|
146
|
+
Option("-g", args=Args.filename[str], help_text="全局图片", action=append),
|
|
147
|
+
meta=CommandMeta(description="重命名图片,按照参数先后判断"),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@s_mvpic.handle()
|
|
152
|
+
async def _(
|
|
153
|
+
bot: Bot,
|
|
154
|
+
event: GroupMessageEvent,
|
|
155
|
+
):
|
|
156
|
+
if not await PIC_AMDIN(bot, event):
|
|
157
|
+
await spic.finish("不支持选项 -m")
|
|
158
|
+
|
|
159
|
+
cmd = a_mvpic.parse(event.message.extract_plain_text())
|
|
160
|
+
if not cmd.matched:
|
|
161
|
+
await s_mvpic.finish(str(cmd.error_info) + "\n\n" + a_mvpic.get_help())
|
|
162
|
+
options = cmd.options
|
|
163
|
+
if not options:
|
|
164
|
+
await s_mvpic.finish("文件名呢?" + "\n\n" + a_mvpic.get_help())
|
|
165
|
+
|
|
166
|
+
sg = "globe" if list(options.keys())[0] == "g" else f"qq_group:{event.group_id}"
|
|
167
|
+
if len(options["g" if sg == "globe" else "l"].args.get("filename", [])) >= 2:
|
|
168
|
+
dg = sg
|
|
169
|
+
else:
|
|
170
|
+
dg = "globe" if sg != "globe" else f"qq_group:{event.group_id}"
|
|
171
|
+
if ("g" if dg == "globe" else "l") not in options:
|
|
172
|
+
await s_mvpic.finish("至多只有一个文件名哦?" + "\n\n" + a_mvpic.get_help())
|
|
173
|
+
|
|
174
|
+
sname = options["g" if sg == "globe" else "l"].args["filename"][0]
|
|
175
|
+
dname = options["g" if dg == "globe" else "l"].args["filename"][
|
|
176
|
+
1 if sg == dg else 0
|
|
177
|
+
]
|
|
178
|
+
for c in INVALID_FILENAME_CHARACTERS:
|
|
179
|
+
sname = sname.replace(c, "-")
|
|
180
|
+
dname = dname.replace(c, "-")
|
|
181
|
+
if not sname.endswith((".jpg", ".png", ".gif")):
|
|
182
|
+
sname += ".jpg"
|
|
183
|
+
if not dname.endswith((".jpg", ".png", ".gif")):
|
|
184
|
+
dname += ".jpg"
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
await rename(sname, dname, sg, dg)
|
|
188
|
+
except Exception as ex:
|
|
189
|
+
await spic.finish(str(ex))
|
|
190
|
+
await spic.finish("图片已重命名")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from nonebot import on_message
|
|
2
|
+
from nonebot.adapters.onebot.v11.event import MessageEvent
|
|
3
|
+
from nonebot.internal.adapter.bot import Bot
|
|
4
|
+
from nonebot.adapters.onebot.v11.message import MessageSegment as V11Seg
|
|
5
|
+
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
|
|
6
|
+
|
|
7
|
+
from .pic_sql import load_pic, select_pic
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def endswith_pic(event: MessageEvent):
|
|
11
|
+
text = event.message.extract_plain_text().strip()
|
|
12
|
+
if " " in text:
|
|
13
|
+
return False
|
|
14
|
+
return text.endswith((".jpg", ".png", ".gif"))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
pic_listen = on_message(rule=endswith_pic)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pic_listen.handle()
|
|
21
|
+
async def _(bot: Bot, event: MessageEvent):
|
|
22
|
+
name = event.message.extract_plain_text().strip()
|
|
23
|
+
group_id = (
|
|
24
|
+
"globe"
|
|
25
|
+
if not isinstance(event, GroupMessageEvent)
|
|
26
|
+
else f"qq_group:{event.group_id}"
|
|
27
|
+
)
|
|
28
|
+
try:
|
|
29
|
+
pic = await select_pic(name, group_id)
|
|
30
|
+
if pic:
|
|
31
|
+
file_ = await load_pic(pic.url)
|
|
32
|
+
await bot.send(event, V11Seg.image(file=file_))
|
|
33
|
+
except Exception as ex:
|
|
34
|
+
await pic_listen.finish(str(ex))
|
{nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/model.py
RENAMED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
from nonebot_plugin_datastore import get_plugin_data
|
|
2
2
|
from sqlalchemy import TEXT
|
|
3
|
+
from sqlalchemy.dialects.postgresql import BIT
|
|
3
4
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
4
5
|
|
|
5
6
|
plugin_data = get_plugin_data()
|
|
6
7
|
plugin_data.use_global_registry()
|
|
7
8
|
Model = plugin_data.Model
|
|
8
9
|
|
|
10
|
+
|
|
9
11
|
class PicData(Model):
|
|
10
12
|
"""消息记录"""
|
|
11
13
|
|
|
14
|
+
__tablename__ = "picdata"
|
|
15
|
+
|
|
12
16
|
__table_args__ = {"extend_existing": True}
|
|
13
17
|
|
|
14
18
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
@@ -17,4 +21,6 @@ class PicData(Model):
|
|
|
17
21
|
group: Mapped[str] = mapped_column(TEXT)
|
|
18
22
|
""" 所属群组 id """
|
|
19
23
|
url: Mapped[str] = mapped_column(TEXT)
|
|
20
|
-
""" 图片目录 """
|
|
24
|
+
""" 图片目录 """
|
|
25
|
+
phash: Mapped[bytes] = mapped_column(BIT(256))
|
|
26
|
+
""" 图片的 phash 值 """
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import sqlalchemy as sa
|
|
2
|
+
from sqlalchemy.ext.asyncio.session import AsyncSession
|
|
3
|
+
from sqlalchemy.ext.asyncio import create_async_engine
|
|
4
|
+
from sqlalchemy import select
|
|
5
|
+
from nonebot import get_driver
|
|
6
|
+
import os
|
|
7
|
+
import random
|
|
8
|
+
import csv
|
|
9
|
+
import hashlib
|
|
10
|
+
from sqlalchemy import cast
|
|
11
|
+
|
|
12
|
+
from .model import PicData, BIT
|
|
13
|
+
from .picture import load_pic, p_hash
|
|
14
|
+
from .config import Config
|
|
15
|
+
|
|
16
|
+
gdriver = get_driver()
|
|
17
|
+
p_config = Config.parse_obj(gdriver.config)
|
|
18
|
+
_async_database = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def AsyncDatabase():
|
|
22
|
+
if not _async_database:
|
|
23
|
+
raise RuntimeError("Database is not initialized")
|
|
24
|
+
return _async_database
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def del_pic(url: str):
|
|
28
|
+
if os.path.exists(url):
|
|
29
|
+
os.remove(url)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def write_pic(url: str, des_dir: str = None) -> str:
|
|
33
|
+
if not des_dir:
|
|
34
|
+
des_dir = "savepic"
|
|
35
|
+
if not os.path.exists(des_dir):
|
|
36
|
+
os.makedirs(des_dir)
|
|
37
|
+
|
|
38
|
+
byte = await load_pic(url)
|
|
39
|
+
filename = hashlib.sha256(byte).hexdigest()
|
|
40
|
+
while os.path.exists(os.path.join(des_dir, filename)):
|
|
41
|
+
filename += "_"
|
|
42
|
+
with open(os.path.join(des_dir, filename), "wb") as f:
|
|
43
|
+
f.write(byte)
|
|
44
|
+
return os.path.join(des_dir, filename)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def select_pic(filename: str, group: str):
|
|
48
|
+
async with AsyncSession(_async_database) as db_session:
|
|
49
|
+
pic = await db_session.scalar(
|
|
50
|
+
select(PicData)
|
|
51
|
+
.where(PicData.name == filename)
|
|
52
|
+
.where(PicData.group == group)
|
|
53
|
+
)
|
|
54
|
+
if pic:
|
|
55
|
+
return pic
|
|
56
|
+
|
|
57
|
+
pic = await db_session.scalar(
|
|
58
|
+
select(PicData)
|
|
59
|
+
.where(PicData.name == filename)
|
|
60
|
+
.where(PicData.group == "globe")
|
|
61
|
+
)
|
|
62
|
+
if pic:
|
|
63
|
+
return pic
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
async def savepic(
|
|
67
|
+
filename: str,
|
|
68
|
+
url: str,
|
|
69
|
+
hash: bytes,
|
|
70
|
+
group_id: str = "globe",
|
|
71
|
+
collision_allow: bool = False,
|
|
72
|
+
):
|
|
73
|
+
pic = PicData(
|
|
74
|
+
group=group_id,
|
|
75
|
+
name=filename,
|
|
76
|
+
url=url,
|
|
77
|
+
phash=hash,
|
|
78
|
+
)
|
|
79
|
+
async with AsyncSession(_async_database) as db_session:
|
|
80
|
+
# select the name == ""
|
|
81
|
+
despic = await select_pic(filename, group_id)
|
|
82
|
+
if despic and despic.group == group_id:
|
|
83
|
+
raise Exception("文件名已存在。")
|
|
84
|
+
despic = await db_session.scalar(
|
|
85
|
+
select(PicData)
|
|
86
|
+
.where(PicData.group == group_id)
|
|
87
|
+
.where(
|
|
88
|
+
sa.func.bit_count(PicData.phash.bitwise_xor(cast(hash, BIT(256)))) <= 7
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
if despic and not collision_allow:
|
|
92
|
+
raise Exception("相似图片已存在。" + "\n" + despic.name)
|
|
93
|
+
|
|
94
|
+
if random.randint(1, 10) == 1:
|
|
95
|
+
empty = await db_session.scalar(select(PicData).where(PicData.name == ""))
|
|
96
|
+
else:
|
|
97
|
+
empty = None
|
|
98
|
+
|
|
99
|
+
if empty:
|
|
100
|
+
empty.group = group_id
|
|
101
|
+
empty.url = url
|
|
102
|
+
empty.name = filename
|
|
103
|
+
empty.phash = pic.phash
|
|
104
|
+
await db_session.merge(empty)
|
|
105
|
+
else:
|
|
106
|
+
db_session.add(pic)
|
|
107
|
+
await db_session.commit()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
async def init_db():
|
|
111
|
+
# check if the table exists
|
|
112
|
+
global _async_database
|
|
113
|
+
_async_database = create_async_engine(
|
|
114
|
+
p_config.savepic_sqlurl, pool_pre_ping=True, pool_size=25, max_overflow=20
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
metadata = sa.MetaData()
|
|
119
|
+
table = sa.Table(
|
|
120
|
+
"picdata",
|
|
121
|
+
metadata,
|
|
122
|
+
sa.Column("id", sa.Integer, primary_key=True),
|
|
123
|
+
sa.Column("name", sa.TEXT, nullable=False),
|
|
124
|
+
sa.Column("group", sa.TEXT, nullable=False),
|
|
125
|
+
sa.Column("url", sa.TEXT, nullable=False),
|
|
126
|
+
sa.Column("phash", BIT(256), nullable=False),
|
|
127
|
+
)
|
|
128
|
+
async with _async_database.begin() as conn:
|
|
129
|
+
await conn.run_sync(metadata.create_all)
|
|
130
|
+
except Exception:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@gdriver.on_startup
|
|
135
|
+
async def _():
|
|
136
|
+
if not p_config.savepic_sqlurl:
|
|
137
|
+
raise Exception("请配置 savepic_sqlurl")
|
|
138
|
+
|
|
139
|
+
await init_db()
|
|
140
|
+
if os.path.exists("savepic_picdata.csv"):
|
|
141
|
+
# 加载旧版数据
|
|
142
|
+
print("加载旧版数据")
|
|
143
|
+
failed = []
|
|
144
|
+
with open("savepic_picdata.csv", "r") as f:
|
|
145
|
+
for i in csv.reader(f):
|
|
146
|
+
_, name, group, url = i
|
|
147
|
+
if not name or url == "url":
|
|
148
|
+
continue
|
|
149
|
+
t = await select_pic(name, group)
|
|
150
|
+
if t and t.group == group:
|
|
151
|
+
continue
|
|
152
|
+
p_hash_ = p_hash(await load_pic(url))
|
|
153
|
+
print(i)
|
|
154
|
+
try:
|
|
155
|
+
await savepic(name, url, p_hash_, group, True)
|
|
156
|
+
except Exception as ex:
|
|
157
|
+
print(ex)
|
|
158
|
+
failed.append(i)
|
|
159
|
+
os.remove("savepic_picdata.csv")
|
|
160
|
+
with open("savepic.csv", "w+") as f:
|
|
161
|
+
writer = csv.writer(f)
|
|
162
|
+
writer.writerow(["id", "name", "group", "url"])
|
|
163
|
+
for i in failed:
|
|
164
|
+
writer.writerow(i)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def rename(ori: str, des: str, s_group: str, d_group: str):
|
|
168
|
+
async with AsyncSession(_async_database) as db_session:
|
|
169
|
+
pic = await db_session.scalar(
|
|
170
|
+
select(PicData)
|
|
171
|
+
.where(PicData.name == ori)
|
|
172
|
+
.where(sa.or_(PicData.group == s_group, PicData.group == "globe"))
|
|
173
|
+
)
|
|
174
|
+
if not pic:
|
|
175
|
+
raise Exception("重命名失败,没有找到图片")
|
|
176
|
+
despic = await db_session.scalar(
|
|
177
|
+
select(PicData).where(
|
|
178
|
+
sa.and_(PicData.name == des, PicData.group == d_group)
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
if despic:
|
|
182
|
+
raise Exception("重命名失败,目标文件名已存在")
|
|
183
|
+
pic.name = des
|
|
184
|
+
pic.group = d_group
|
|
185
|
+
|
|
186
|
+
await db_session.merge(pic)
|
|
187
|
+
await db_session.commit()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
async def delete(filename: str, group: str):
|
|
191
|
+
async with AsyncSession(_async_database) as db_session:
|
|
192
|
+
pic = await db_session.scalar(
|
|
193
|
+
select(PicData).where(
|
|
194
|
+
sa.and_(PicData.name == filename, PicData.group == group)
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
if pic:
|
|
198
|
+
del_pic(pic.url)
|
|
199
|
+
pic.name = ""
|
|
200
|
+
await db_session.merge(pic)
|
|
201
|
+
await db_session.commit()
|
|
202
|
+
else:
|
|
203
|
+
raise Exception("删除失败,没有找到图片")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
async def randpic(reg: str, group: str = "globe") -> PicData:
|
|
207
|
+
reg = reg.strip()
|
|
208
|
+
if not reg:
|
|
209
|
+
reg = ".*"
|
|
210
|
+
async with AsyncSession(_async_database) as db_session:
|
|
211
|
+
pic = await db_session.scalar(
|
|
212
|
+
select(PicData)
|
|
213
|
+
.where(sa.or_(PicData.group == group, PicData.group == "globe"))
|
|
214
|
+
.where(PicData.name != "")
|
|
215
|
+
.order_by(sa.func.random())
|
|
216
|
+
.where(PicData.name.regexp_match(reg))
|
|
217
|
+
)
|
|
218
|
+
if pic:
|
|
219
|
+
return pic
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import scipy.fftpack as fft
|
|
2
|
+
import numpy as np
|
|
3
|
+
import httpx
|
|
4
|
+
import os
|
|
5
|
+
from PIL import Image
|
|
6
|
+
from io import BytesIO
|
|
7
|
+
|
|
8
|
+
_httpx_async = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def remove_alpha(im: Image) -> Image:
|
|
12
|
+
# Only process if image has transparency (http://stackoverflow.com/a/1963146)
|
|
13
|
+
if im.mode in ("RGBA", "LA") or (im.mode == "P" and "transparency" in im.info):
|
|
14
|
+
# Need to convert to RGBA if LA format due to a bug in PIL (http://stackoverflow.com/a/1963146)
|
|
15
|
+
alpha = im.convert("RGBA").split()[-1]
|
|
16
|
+
|
|
17
|
+
# Create a new background image of our matt color.
|
|
18
|
+
# Must be RGBA because paste requires both images have the same format
|
|
19
|
+
# (http://stackoverflow.com/a/8720632 and http://stackoverflow.com/a/9459208)
|
|
20
|
+
bg = Image.new("RGBA", im.size, (255, 255, 255) + (255,))
|
|
21
|
+
bg.paste(im, mask=alpha)
|
|
22
|
+
return bg
|
|
23
|
+
|
|
24
|
+
else:
|
|
25
|
+
return im
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def load_pic(url: str) -> bytes:
|
|
29
|
+
global _httpx_async
|
|
30
|
+
if url.startswith("http"):
|
|
31
|
+
if not _httpx_async:
|
|
32
|
+
_httpx_async = httpx.AsyncClient()
|
|
33
|
+
resp = await _httpx_async.get(url)
|
|
34
|
+
resp.raise_for_status()
|
|
35
|
+
return resp.content
|
|
36
|
+
if os.path.exists(url):
|
|
37
|
+
with open(url, "rb") as f:
|
|
38
|
+
return f.read()
|
|
39
|
+
raise Exception("不支持的 URL")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def p_hash(img: bytes) -> bytes:
|
|
43
|
+
pic = remove_alpha(
|
|
44
|
+
Image.open(BytesIO(img)).resize((128, 128), Image.Resampling.LANCZOS)
|
|
45
|
+
).convert("L")
|
|
46
|
+
dct = fft.dct(np.array(pic))
|
|
47
|
+
average = np.median(dct)
|
|
48
|
+
return np.packbits(dct[:16, :16] > average).tobytes()
|
{nonebot_plugin_savepic-0.1.2 → nonebot_plugin_savepic-0.2.0}/nonebot_plugin_savepic/rule.py
RENAMED
|
@@ -4,8 +4,8 @@ This module is used to define the permission of the bot.
|
|
|
4
4
|
|
|
5
5
|
import nonebot
|
|
6
6
|
from nonebot.adapters import Bot, Event
|
|
7
|
-
from nonebot_plugin_datastore import get_plugin_data
|
|
8
7
|
from nonebot.internal.permission import Permission
|
|
8
|
+
|
|
9
9
|
from .config import Config
|
|
10
10
|
|
|
11
11
|
global_config = nonebot.get_driver().config
|
|
@@ -32,4 +32,4 @@ class Savepic_Admin(Permission):
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
PIC_AMDIN = Permission(Savepic_Admin())
|
|
35
|
+
PIC_AMDIN = Permission(Savepic_Admin())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "nonebot-plugin-savepic"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "保存表情包(语录)与随机出图"
|
|
5
5
|
authors = ["Yan <1964649083@qq.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -9,11 +9,15 @@ packages = [{include = "nonebot_plugin_savepic"}]
|
|
|
9
9
|
homepage = "https://github.com/Yan-Zero/nonebot-plugin-savepic"
|
|
10
10
|
|
|
11
11
|
[tool.poetry.dependencies]
|
|
12
|
-
python = "^3.10"
|
|
12
|
+
python = "^3.10, <3.13"
|
|
13
13
|
nonebot2 = "^2.0.1"
|
|
14
14
|
nonebot-plugin-datastore = "^1.1.0"
|
|
15
15
|
asyncpg = "^0.28.0"
|
|
16
16
|
nonebot-adapter-onebot = "^2.2.3"
|
|
17
|
+
arclet-alconna = "^1.7.14"
|
|
18
|
+
numpy = "^1.25.2"
|
|
19
|
+
scipy = "^1.11.1"
|
|
20
|
+
pillow = "^10.0.0"
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
[build-system]
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
from nonebot import require
|
|
2
|
-
from nonebot import get_driver
|
|
3
|
-
|
|
4
|
-
require("nonebot_plugin_datastore")
|
|
5
|
-
|
|
6
|
-
from nonebot import on_command, on_message
|
|
7
|
-
from nonebot.params import CommandArg, Arg
|
|
8
|
-
from nonebot.adapters.onebot.v11.message import Message as V11Msg
|
|
9
|
-
from nonebot.adapters.onebot.v11.message import MessageSegment as V11Seg
|
|
10
|
-
from nonebot.adapters.onebot.v11 import Bot
|
|
11
|
-
from nonebot.adapters.onebot.v11.event import MessageEvent
|
|
12
|
-
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
|
|
13
|
-
from nonebot.matcher import Matcher
|
|
14
|
-
from nonebot.typing import T_State
|
|
15
|
-
|
|
16
|
-
from asyncpg.exceptions import InvalidRegularExpressionError
|
|
17
|
-
|
|
18
|
-
from .config import Config
|
|
19
|
-
from .pic_sql import savepic, rename, delete, write_pic, randpic, load_pic, select_pic
|
|
20
|
-
from .rule import PIC_AMDIN
|
|
21
|
-
|
|
22
|
-
from nonebot.plugin import PluginMetadata
|
|
23
|
-
|
|
24
|
-
__plugin_meta__ = PluginMetadata(
|
|
25
|
-
name="Savepic",
|
|
26
|
-
description="表情包保存",
|
|
27
|
-
usage="""用法:
|
|
28
|
-
/savepic <文件名> <图片>
|
|
29
|
-
/savepic -g <文件名> <全局图片>
|
|
30
|
-
/savepic -d <文件名> 删除图图片
|
|
31
|
-
/savepic -m <原文件名> <新文件名> 重命名图片
|
|
32
|
-
/randpic <关键词> 随机图片
|
|
33
|
-
<文件名> 发送图片""",
|
|
34
|
-
config=Config,
|
|
35
|
-
homepage="https://github.com/Yan-Zero/nonebot-plugin-savepic",
|
|
36
|
-
type="application",
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
INVALID_FILENAME_CHARACTERS = r'\/:*?"<>|'
|
|
40
|
-
|
|
41
|
-
global_config = get_driver().config
|
|
42
|
-
p_config = Config.parse_obj(global_config)
|
|
43
|
-
|
|
44
|
-
rpic = on_command("randpic", aliases={"随机图"}, priority=5)
|
|
45
|
-
@rpic.handle()
|
|
46
|
-
async def _(bot: Bot, event, args: V11Msg = CommandArg()):
|
|
47
|
-
reg = args.extract_plain_text().strip()
|
|
48
|
-
group_id = 'globe' if not isinstance(event, GroupMessageEvent) else f"qq_group:{event.group_id}"
|
|
49
|
-
try:
|
|
50
|
-
pic = await randpic(reg, group_id)
|
|
51
|
-
if pic:
|
|
52
|
-
file_ = await load_pic(pic.url)
|
|
53
|
-
await bot.send(event, V11Msg([pic.name + "\n", V11Seg.image(file=file_)]))
|
|
54
|
-
except InvalidRegularExpressionError:
|
|
55
|
-
await rpic.finish('正则表达式错误')
|
|
56
|
-
except Exception as ex:
|
|
57
|
-
await rpic.finish(str(ex))
|
|
58
|
-
|
|
59
|
-
spic = on_command("savepic", aliases={"存图"}, priority=5)
|
|
60
|
-
@spic.handle()
|
|
61
|
-
async def _(bot: Bot, matcher: Matcher, event: GroupMessageEvent, state: T_State, args: V11Msg = CommandArg()):
|
|
62
|
-
if not args:
|
|
63
|
-
await spic.finish('''用法:
|
|
64
|
-
/savepic <文件名> <图片>
|
|
65
|
-
/savepic -g <文件名> <全局图片>
|
|
66
|
-
/savepic -d <文件名> 删除图图片
|
|
67
|
-
/savepic -m <原文件名> <新文件名> 重命名图片''')
|
|
68
|
-
params = args.extract_plain_text().strip().split()
|
|
69
|
-
state['savepiv_group'] = 'globe' if '-g' in params and await PIC_AMDIN(bot, event) else f"qq_group:{event.group_id}"
|
|
70
|
-
_d = '-d' in params
|
|
71
|
-
_m = '-m' in params
|
|
72
|
-
if _d:
|
|
73
|
-
params.remove('-d')
|
|
74
|
-
if _m:
|
|
75
|
-
params.remove('-m')
|
|
76
|
-
if '-g' in params:
|
|
77
|
-
params.remove('-g')
|
|
78
|
-
|
|
79
|
-
if not params:
|
|
80
|
-
await spic.finish("文件名?")
|
|
81
|
-
filename = params[0].strip()
|
|
82
|
-
for c in INVALID_FILENAME_CHARACTERS:
|
|
83
|
-
filename = filename.replace(c, "-")
|
|
84
|
-
if not filename.endswith(('.jpg', '.png', '.gif')):
|
|
85
|
-
filename += '.jpg'
|
|
86
|
-
|
|
87
|
-
if _d:
|
|
88
|
-
if not await PIC_AMDIN(bot, event):
|
|
89
|
-
await spic.finish('不支持选项 -d')
|
|
90
|
-
try:
|
|
91
|
-
await delete(filename, state['savepiv_group'])
|
|
92
|
-
except Exception as ex:
|
|
93
|
-
await spic.finish(str(ex))
|
|
94
|
-
await spic.finish('图片已删除')
|
|
95
|
-
|
|
96
|
-
if _m:
|
|
97
|
-
if not await PIC_AMDIN(bot, event):
|
|
98
|
-
await spic.finish('不支持选项 -m')
|
|
99
|
-
if len(params) <= 1:
|
|
100
|
-
await spic.finish("目标文件名?")
|
|
101
|
-
for c in INVALID_FILENAME_CHARACTERS:
|
|
102
|
-
params[1] = params[1].replace(c, "-")
|
|
103
|
-
if not params[1].endswith(('.jpg', '.png', '.gif')):
|
|
104
|
-
params[1] += '.jpg'
|
|
105
|
-
|
|
106
|
-
try:
|
|
107
|
-
await rename(filename, params[1], f"qq_group:{event.group_id}", state['savepiv_group'])
|
|
108
|
-
except Exception as ex:
|
|
109
|
-
await spic.finish(str(ex))
|
|
110
|
-
await spic.finish('图片已重命名')
|
|
111
|
-
|
|
112
|
-
pic = await select_pic(filename, state['savepiv_group'])
|
|
113
|
-
if pic and pic.group == state['savepiv_group']:
|
|
114
|
-
spic.finish("图片已存在。")
|
|
115
|
-
picture = args.get('image')
|
|
116
|
-
state['savepiv_filename'] = filename
|
|
117
|
-
if not picture and event.reply:
|
|
118
|
-
picture = event.reply.message.get('image')
|
|
119
|
-
if picture:
|
|
120
|
-
matcher.set_arg('picture', picture)
|
|
121
|
-
|
|
122
|
-
@spic.got('picture', "图呢?")
|
|
123
|
-
async def _(bot: Bot, event: GroupMessageEvent, state: T_State, picture: V11Msg = Arg()):
|
|
124
|
-
picture = picture.get('image')
|
|
125
|
-
if not picture:
|
|
126
|
-
await spic.finish('6,这也不是图啊')
|
|
127
|
-
try:
|
|
128
|
-
dir = await write_pic(picture[0].data['url'], p_config.savepic_dir)
|
|
129
|
-
except Exception as ex:
|
|
130
|
-
await spic.finish("存图失败。" + '\n' + str(ex))
|
|
131
|
-
try:
|
|
132
|
-
await savepic(state['savepiv_filename'], dir, state['savepiv_group'])
|
|
133
|
-
await spic.send("保存成功")
|
|
134
|
-
except Exception as ex:
|
|
135
|
-
await spic.finish(str(ex))
|
|
136
|
-
|
|
137
|
-
async def endswith_pic(event: MessageEvent):
|
|
138
|
-
text = event.message.extract_plain_text().strip()
|
|
139
|
-
if ' ' in text:
|
|
140
|
-
return False
|
|
141
|
-
return text.endswith(('.jpg', '.png', '.gif'))
|
|
142
|
-
|
|
143
|
-
pic_listen = on_message(rule=endswith_pic)
|
|
144
|
-
@pic_listen.handle()
|
|
145
|
-
async def _(bot: Bot, event: MessageEvent):
|
|
146
|
-
name = event.message.extract_plain_text().strip()
|
|
147
|
-
group_id = 'globe' if not isinstance(event, GroupMessageEvent) else f"qq_group:{event.group_id}"
|
|
148
|
-
try:
|
|
149
|
-
pic = await select_pic(name, group_id)
|
|
150
|
-
if pic:
|
|
151
|
-
file_ = await load_pic(pic.url)
|
|
152
|
-
await bot.send(event, V11Seg.image(file=file_))
|
|
153
|
-
except Exception as ex:
|
|
154
|
-
await rpic.finish(str(ex))
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
from nonebot_plugin_datastore import create_session
|
|
2
|
-
import sqlalchemy as sa
|
|
3
|
-
from sqlalchemy import select, update
|
|
4
|
-
import hashlib
|
|
5
|
-
import httpx
|
|
6
|
-
import os
|
|
7
|
-
import random
|
|
8
|
-
from sqlalchemy.sql import func
|
|
9
|
-
from nonebot_plugin_datastore.db import post_db_init
|
|
10
|
-
|
|
11
|
-
from .model import PicData
|
|
12
|
-
|
|
13
|
-
httpx_async = None
|
|
14
|
-
|
|
15
|
-
async def load_pic(url: str)-> bytes:
|
|
16
|
-
global httpx_async
|
|
17
|
-
if url.startswith("http"):
|
|
18
|
-
if not httpx_async:
|
|
19
|
-
httpx_async = httpx.AsyncClient()
|
|
20
|
-
resp = await httpx_async.get(url)
|
|
21
|
-
resp.raise_for_status()
|
|
22
|
-
return resp.content
|
|
23
|
-
if os.path.exists(url):
|
|
24
|
-
with open(url, 'rb') as f:
|
|
25
|
-
return f.read()
|
|
26
|
-
raise Exception("不支持的统一资源定位器")
|
|
27
|
-
|
|
28
|
-
def del_pic(url: str):
|
|
29
|
-
if os.path.exists(url):
|
|
30
|
-
os.remove(url)
|
|
31
|
-
|
|
32
|
-
async def write_pic(url: str, des_dir: str = None) -> str:
|
|
33
|
-
if not des_dir:
|
|
34
|
-
des_dir = 'savepic'
|
|
35
|
-
if not os.path.exists(des_dir):
|
|
36
|
-
os.makedirs(des_dir)
|
|
37
|
-
|
|
38
|
-
byte = await load_pic(url)
|
|
39
|
-
filename = hashlib.sha256(byte).hexdigest()
|
|
40
|
-
while os.path.exists(os.path.join(des_dir, filename)):
|
|
41
|
-
filename = hashlib.sha256((filename + str(random.randint(0, 100000))).encode()).hexdigest()
|
|
42
|
-
with open(os.path.join(des_dir, filename), 'wb+') as f:
|
|
43
|
-
f.write(byte)
|
|
44
|
-
return os.path.join(des_dir, filename)
|
|
45
|
-
|
|
46
|
-
async def select_pic(filename: str, group: str):
|
|
47
|
-
async with create_session() as db_session:
|
|
48
|
-
pic = await db_session.scalar(select(PicData)
|
|
49
|
-
.where(PicData.name == filename)
|
|
50
|
-
.where(PicData.group == group))
|
|
51
|
-
if pic:
|
|
52
|
-
return pic
|
|
53
|
-
|
|
54
|
-
pic = await db_session.scalar(select(PicData)
|
|
55
|
-
.where(PicData.name == filename)
|
|
56
|
-
.where(PicData.group == 'globe'))
|
|
57
|
-
if pic:
|
|
58
|
-
return pic
|
|
59
|
-
|
|
60
|
-
async def savepic(filename: str, dir: str, group_id: str):
|
|
61
|
-
pic = PicData(
|
|
62
|
-
group = group_id,
|
|
63
|
-
name = filename,
|
|
64
|
-
url = dir,
|
|
65
|
-
)
|
|
66
|
-
async with create_session() as db_session:
|
|
67
|
-
# select the name == ""
|
|
68
|
-
despic = await select_pic(filename, group_id)
|
|
69
|
-
if despic and despic.group == group_id:
|
|
70
|
-
raise Exception("文件名已存在。")
|
|
71
|
-
|
|
72
|
-
if random.randint(1, 10) == 1:
|
|
73
|
-
empty = await db_session.scalar(select(PicData).where(PicData.name == ""))
|
|
74
|
-
else:
|
|
75
|
-
empty = None
|
|
76
|
-
|
|
77
|
-
if empty:
|
|
78
|
-
empty.group = group_id
|
|
79
|
-
empty.url = dir
|
|
80
|
-
empty.name = filename
|
|
81
|
-
await db_session.merge(empty)
|
|
82
|
-
else:
|
|
83
|
-
db_session.add(pic)
|
|
84
|
-
await db_session.commit()
|
|
85
|
-
|
|
86
|
-
@post_db_init
|
|
87
|
-
async def init():
|
|
88
|
-
if not os.path.exists('history_savepic'):
|
|
89
|
-
return
|
|
90
|
-
for root, dirs, files in os.walk('history_savepic'):
|
|
91
|
-
group = root.split('/')[-1]
|
|
92
|
-
for file in files:
|
|
93
|
-
dir = os.path.join("savepic", file.replace(' ', ''))
|
|
94
|
-
if os.path.exists(dir):
|
|
95
|
-
dir = await write_pic(os.path.join(root, file))
|
|
96
|
-
os.remove(os.path.join(root, file))
|
|
97
|
-
else:
|
|
98
|
-
os.rename(os.path.join(root, file), dir)
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
await savepic(file, dir, group)
|
|
102
|
-
print(f"save {file} to {group}")
|
|
103
|
-
except Exception as ex:
|
|
104
|
-
print(ex)
|
|
105
|
-
os.remove(dir)
|
|
106
|
-
|
|
107
|
-
async def rename(ori: str, des: str, s_group: str, d_group: str):
|
|
108
|
-
async with create_session() as db_session:
|
|
109
|
-
pic = await db_session.scalar(select(PicData).where(
|
|
110
|
-
PicData.name == ori
|
|
111
|
-
).where(sa.or_(PicData.group == s_group, PicData.group == "globe")))
|
|
112
|
-
if not pic:
|
|
113
|
-
raise Exception("重命名失败,没有找到图片")
|
|
114
|
-
despic = await db_session.scalar(select(PicData).where(
|
|
115
|
-
sa.and_(PicData.name == des, PicData.group == d_group)
|
|
116
|
-
))
|
|
117
|
-
if despic:
|
|
118
|
-
raise Exception("重命名失败,目标文件名已存在")
|
|
119
|
-
pic.name = des
|
|
120
|
-
pic.group = d_group
|
|
121
|
-
|
|
122
|
-
await db_session.merge(pic)
|
|
123
|
-
await db_session.commit()
|
|
124
|
-
|
|
125
|
-
async def delete(filename: str, group: str):
|
|
126
|
-
async with create_session() as db_session:
|
|
127
|
-
pic = await db_session.scalar(select(PicData).where(
|
|
128
|
-
sa.and_(PicData.name == filename, PicData.group == group)
|
|
129
|
-
))
|
|
130
|
-
if pic:
|
|
131
|
-
del_pic(pic.url)
|
|
132
|
-
pic.name = ""
|
|
133
|
-
await db_session.merge(pic)
|
|
134
|
-
await db_session.commit()
|
|
135
|
-
else:
|
|
136
|
-
raise Exception("删除失败,没有找到图片")
|
|
137
|
-
|
|
138
|
-
async def randpic(reg: str, group: str = "globe") -> PicData:
|
|
139
|
-
reg = reg.strip()
|
|
140
|
-
if not reg:
|
|
141
|
-
reg = ".*"
|
|
142
|
-
async with create_session() as db_session:
|
|
143
|
-
pic = await db_session.scalar(select(PicData)
|
|
144
|
-
.where(sa.or_(PicData.group == group, PicData.group == "globe"))
|
|
145
|
-
.where(PicData.name != "")
|
|
146
|
-
.order_by(func.random())
|
|
147
|
-
.where(PicData.name.regexp_match(reg))
|
|
148
|
-
)
|
|
149
|
-
if pic:
|
|
150
|
-
return pic
|
|
File without changes
|
|
File without changes
|
|
File without changes
|