mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 14:22:55 +08:00
feat✨: PIX图库
This commit is contained in:
parent
c2fd8661b5
commit
c6afb8c1e9
62
zhenxun/plugins/pix_gallery/__init__.py
Normal file
62
zhenxun/plugins/pix_gallery/__init__.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
import nonebot
|
||||||
|
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
|
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"hibiapi",
|
||||||
|
"HIBIAPI",
|
||||||
|
"https://api.obfs.dev",
|
||||||
|
help="如果没有自建或其他hibiapi请不要修改",
|
||||||
|
default_value="https://api.obfs.dev",
|
||||||
|
)
|
||||||
|
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pximg.cf", help="Pixiv反向代理")
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix",
|
||||||
|
"PIX_IMAGE_SIZE",
|
||||||
|
"master",
|
||||||
|
help="PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)",
|
||||||
|
default_value="master",
|
||||||
|
)
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix",
|
||||||
|
"SEARCH_HIBIAPI_BOOKMARKS",
|
||||||
|
5000,
|
||||||
|
help="最低收藏,PIX使用HIBIAPI搜索图片时达到最低收藏才会添加至图库",
|
||||||
|
default_value=5000,
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix",
|
||||||
|
"WITHDRAW_PIX_MESSAGE",
|
||||||
|
(0, 1),
|
||||||
|
help="自动撤回,参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
|
||||||
|
default_value=(0, 1),
|
||||||
|
type=Tuple[int, int],
|
||||||
|
)
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix",
|
||||||
|
"PIX_OMEGA_PIXIV_RATIO",
|
||||||
|
(10, 0),
|
||||||
|
help="PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为0)",
|
||||||
|
default_value=(10, 0),
|
||||||
|
type=Tuple[int, int],
|
||||||
|
)
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix", "TIMEOUT", 10, help="下载图片超时限制(秒)", default_value=10, type=int
|
||||||
|
)
|
||||||
|
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"pix",
|
||||||
|
"SHOW_INFO",
|
||||||
|
True,
|
||||||
|
help="是否显示图片的基本信息,如PID等",
|
||||||
|
default_value=True,
|
||||||
|
type=bool,
|
||||||
|
)
|
||||||
|
|
||||||
|
Config.set_name("pix", "PIX图库")
|
||||||
|
|
||||||
|
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
|
||||||
426
zhenxun/plugins/pix_gallery/_data_source.py
Normal file
426
zhenxun/plugins/pix_gallery/_data_source.py
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
import asyncio
|
||||||
|
import math
|
||||||
|
from asyncio.exceptions import TimeoutError
|
||||||
|
from asyncio.locks import Semaphore
|
||||||
|
from copy import deepcopy
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
from httpx import ConnectError
|
||||||
|
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
|
from zhenxun.configs.path_config import TEMP_PATH
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.http_utils import AsyncHttpx
|
||||||
|
from zhenxun.utils.image_utils import BuildImage
|
||||||
|
from zhenxun.utils.utils import change_img_md5, change_pixiv_image_links
|
||||||
|
|
||||||
|
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
|
||||||
|
from ._model.pixiv import Pixiv
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
|
||||||
|
" rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
|
||||||
|
"Referer": "https://www.pixiv.net/",
|
||||||
|
}
|
||||||
|
|
||||||
|
HIBIAPI = Config.get_config("hibiapi", "HIBIAPI")
|
||||||
|
if not HIBIAPI:
|
||||||
|
HIBIAPI = "https://api.obfs.dev"
|
||||||
|
HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
|
||||||
|
|
||||||
|
|
||||||
|
async def start_update_image_url(
|
||||||
|
current_keyword: list[str], black_pid: list[str], is_pid: bool
|
||||||
|
) -> tuple[int, int]:
|
||||||
|
"""开始更新图片url
|
||||||
|
|
||||||
|
参数:
|
||||||
|
current_keyword: 关键词
|
||||||
|
black_pid: 黑名单pid
|
||||||
|
is_pid: pid强制更新不受限制
|
||||||
|
|
||||||
|
返回:
|
||||||
|
tuple[int, int]: pid数量和图片数量
|
||||||
|
"""
|
||||||
|
global HIBIAPI
|
||||||
|
pid_count = 0
|
||||||
|
pic_count = 0
|
||||||
|
tasks = []
|
||||||
|
semaphore = asyncio.Semaphore(10)
|
||||||
|
for keyword in current_keyword:
|
||||||
|
for page in range(1, 110):
|
||||||
|
if keyword.startswith("uid:"):
|
||||||
|
url = f"{HIBIAPI}/api/pixiv/member_illust"
|
||||||
|
params = {"id": keyword[4:], "page": page}
|
||||||
|
if page == 30:
|
||||||
|
break
|
||||||
|
elif keyword.startswith("pid:"):
|
||||||
|
url = f"{HIBIAPI}/api/pixiv/illust"
|
||||||
|
params = {"id": keyword[4:]}
|
||||||
|
else:
|
||||||
|
url = f"{HIBIAPI}/api/pixiv/search"
|
||||||
|
params = {"word": keyword, "page": page}
|
||||||
|
tasks.append(
|
||||||
|
asyncio.ensure_future(
|
||||||
|
search_image(
|
||||||
|
url, keyword, params, semaphore, page, black_pid, is_pid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if keyword.startswith("pid:"):
|
||||||
|
break
|
||||||
|
result = await asyncio.gather(*tasks)
|
||||||
|
for x in result:
|
||||||
|
pid_count += x[0]
|
||||||
|
pic_count += x[1]
|
||||||
|
return pid_count, pic_count
|
||||||
|
|
||||||
|
|
||||||
|
async def search_image(
|
||||||
|
url: str,
|
||||||
|
keyword: str,
|
||||||
|
params: dict,
|
||||||
|
semaphore: Semaphore,
|
||||||
|
page: int = 1,
|
||||||
|
black: list[str] = [],
|
||||||
|
is_pid: bool = False,
|
||||||
|
) -> tuple[int, int]:
|
||||||
|
"""搜索图片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
url: 搜索url
|
||||||
|
keyword: 关键词
|
||||||
|
params: params参数
|
||||||
|
semaphore: semaphore
|
||||||
|
page: 页面
|
||||||
|
black: pid黑名单
|
||||||
|
is_pid: pid强制更新不受限制
|
||||||
|
|
||||||
|
返回:
|
||||||
|
tuple[int, int]: pid数量和图片数量
|
||||||
|
"""
|
||||||
|
tmp_pid = []
|
||||||
|
pic_count = 0
|
||||||
|
pid_count = 0
|
||||||
|
async with semaphore:
|
||||||
|
# try:
|
||||||
|
data = (await AsyncHttpx.get(url, params=params)).json()
|
||||||
|
if (
|
||||||
|
not data
|
||||||
|
or data.get("error")
|
||||||
|
or (not data.get("illusts") and not data.get("illust"))
|
||||||
|
):
|
||||||
|
return 0, 0
|
||||||
|
if url != f"{HIBIAPI}/api/pixiv/illust":
|
||||||
|
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
|
||||||
|
data = data["illusts"]
|
||||||
|
else:
|
||||||
|
logger.info(f'获取数据成功...PID:{params.get("id")}')
|
||||||
|
data = [data["illust"]]
|
||||||
|
img_data = {}
|
||||||
|
for x in data:
|
||||||
|
pid = x["id"]
|
||||||
|
title = x["title"]
|
||||||
|
width = x["width"]
|
||||||
|
height = x["height"]
|
||||||
|
view = x["total_view"]
|
||||||
|
bookmarks = x["total_bookmarks"]
|
||||||
|
uid = x["user"]["id"]
|
||||||
|
author = x["user"]["name"]
|
||||||
|
tags = []
|
||||||
|
for tag in x["tags"]:
|
||||||
|
for i in tag:
|
||||||
|
if tag[i]:
|
||||||
|
tags.append(tag[i])
|
||||||
|
img_urls = []
|
||||||
|
if x["page_count"] == 1:
|
||||||
|
img_urls.append(x["meta_single_page"]["original_image_url"])
|
||||||
|
else:
|
||||||
|
for urls in x["meta_pages"]:
|
||||||
|
img_urls.append(urls["image_urls"]["original"])
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
bookmarks >= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS")
|
||||||
|
or (
|
||||||
|
url == f"{HIBIAPI}/api/pixiv/member_illust"
|
||||||
|
and bookmarks >= 1500
|
||||||
|
)
|
||||||
|
or (url == f"{HIBIAPI}/api/pixiv/illust")
|
||||||
|
)
|
||||||
|
and len(img_urls) < 10
|
||||||
|
and _check_black(img_urls, black)
|
||||||
|
) or is_pid:
|
||||||
|
img_data[pid] = {
|
||||||
|
"pid": pid,
|
||||||
|
"title": title,
|
||||||
|
"width": width,
|
||||||
|
"height": height,
|
||||||
|
"view": view,
|
||||||
|
"bookmarks": bookmarks,
|
||||||
|
"img_urls": img_urls,
|
||||||
|
"uid": uid,
|
||||||
|
"author": author,
|
||||||
|
"tags": tags,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
for x in img_data.keys():
|
||||||
|
data = img_data[x]
|
||||||
|
data_copy = deepcopy(data)
|
||||||
|
del data_copy["img_urls"]
|
||||||
|
for img_url in data["img_urls"]:
|
||||||
|
img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")]
|
||||||
|
data_copy["img_url"] = img_url
|
||||||
|
data_copy["img_p"] = img_p
|
||||||
|
data_copy["is_r18"] = "R-18" in data["tags"]
|
||||||
|
if not await Pixiv.exists(
|
||||||
|
pid=data["pid"], img_url=img_url, img_p=img_p
|
||||||
|
):
|
||||||
|
data_copy["img_url"] = img_url
|
||||||
|
await Pixiv.create(**data_copy)
|
||||||
|
if data["pid"] not in tmp_pid:
|
||||||
|
pid_count += 1
|
||||||
|
tmp_pid.append(data["pid"])
|
||||||
|
pic_count += 1
|
||||||
|
logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}')
|
||||||
|
else:
|
||||||
|
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.warning(f"PIX在线搜索图片错误,已再次调用 {type(e)}:{e}")
|
||||||
|
# await search_image(url, keyword, params, semaphore, page, black)
|
||||||
|
return pid_count, pic_count
|
||||||
|
|
||||||
|
|
||||||
|
async def get_image(img_url: str, user_id: str) -> str | Path | None:
|
||||||
|
"""下载图片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
img_url: 图片url
|
||||||
|
user_id: 用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str | Path | None: 图片名称
|
||||||
|
"""
|
||||||
|
if "https://www.pixiv.net/artworks" in img_url:
|
||||||
|
pid = img_url.rsplit("/", maxsplit=1)[-1]
|
||||||
|
params = {"id": pid}
|
||||||
|
for _ in range(3):
|
||||||
|
try:
|
||||||
|
response = await AsyncHttpx.get(
|
||||||
|
f"{HIBIAPI}/api/pixiv/illust", params=params
|
||||||
|
)
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if data.get("illust"):
|
||||||
|
if data["illust"]["page_count"] == 1:
|
||||||
|
img_url = data["illust"]["meta_single_page"][
|
||||||
|
"original_image_url"
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
img_url = data["illust"]["meta_pages"][0]["image_urls"][
|
||||||
|
"original"
|
||||||
|
]
|
||||||
|
break
|
||||||
|
except TimeoutError:
|
||||||
|
pass
|
||||||
|
old_img_url = img_url
|
||||||
|
img_url = change_pixiv_image_links(
|
||||||
|
img_url,
|
||||||
|
Config.get_config("pix", "PIX_IMAGE_SIZE"),
|
||||||
|
Config.get_config("pixiv", "PIXIV_NGINX_URL"),
|
||||||
|
)
|
||||||
|
old_img_url = change_pixiv_image_links(
|
||||||
|
old_img_url, None, Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
||||||
|
)
|
||||||
|
for _ in range(3):
|
||||||
|
try:
|
||||||
|
response = await AsyncHttpx.get(
|
||||||
|
img_url,
|
||||||
|
headers=headers,
|
||||||
|
timeout=Config.get_config("pix", "TIMEOUT"),
|
||||||
|
)
|
||||||
|
if response.status_code == 404:
|
||||||
|
img_url = old_img_url
|
||||||
|
continue
|
||||||
|
async with aiofiles.open(
|
||||||
|
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb"
|
||||||
|
) as f:
|
||||||
|
await f.write(response.content)
|
||||||
|
change_img_md5(
|
||||||
|
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
|
||||||
|
)
|
||||||
|
return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
|
||||||
|
except TimeoutError:
|
||||||
|
logger.warning(f"PIX:{img_url} 图片下载超时...")
|
||||||
|
except ConnectError:
|
||||||
|
logger.warning(f"PIX:{img_url} 图片下载连接失败...")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def uid_pid_exists(id_: str) -> bool:
|
||||||
|
"""检测 pid/uid 是否有效
|
||||||
|
|
||||||
|
参数:
|
||||||
|
id_: pid/uid
|
||||||
|
|
||||||
|
返回:
|
||||||
|
bool: 是否有效
|
||||||
|
"""
|
||||||
|
if id_.startswith("uid:"):
|
||||||
|
url = f"{HIBIAPI}/api/pixiv/member"
|
||||||
|
elif id_.startswith("pid:"):
|
||||||
|
url = f"{HIBIAPI}/api/pixiv/illust"
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
params = {"id": int(id_[4:])}
|
||||||
|
data = (await AsyncHttpx.get(url, params=params)).json()
|
||||||
|
if data.get("error"):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def get_keyword_num(keyword: str) -> tuple[int, int, int, int, int]:
|
||||||
|
"""查看图片相关 tag 数量
|
||||||
|
|
||||||
|
参数:
|
||||||
|
keyword: 关键词tag
|
||||||
|
|
||||||
|
返回:
|
||||||
|
tuple[int, int, int, int, int]: 总数, r18数, Omg图库总数, Omg图库色图数, Omg图库r18数
|
||||||
|
"""
|
||||||
|
count, r18_count = await Pixiv.get_keyword_num(keyword.split())
|
||||||
|
count_, setu_count, r18_count_ = await OmegaPixivIllusts.get_keyword_num(
|
||||||
|
keyword.split()
|
||||||
|
)
|
||||||
|
return count, r18_count, count_, setu_count, r18_count_
|
||||||
|
|
||||||
|
|
||||||
|
async def remove_image(pid: int, img_p: str | None):
|
||||||
|
"""删除置顶图片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
pid: pid
|
||||||
|
img_p: 图片 p 如 p0,p1 等
|
||||||
|
"""
|
||||||
|
if img_p:
|
||||||
|
if "p" not in img_p:
|
||||||
|
img_p = f"p{img_p}"
|
||||||
|
if img_p:
|
||||||
|
await Pixiv.filter(pid=pid, img_p=img_p).delete()
|
||||||
|
else:
|
||||||
|
await Pixiv.filter(pid=pid).delete()
|
||||||
|
|
||||||
|
|
||||||
|
async def gen_keyword_pic(
|
||||||
|
_pass_keyword: list[str], not_pass_keyword: list[str], is_superuser: bool
|
||||||
|
) -> BuildImage:
|
||||||
|
"""已通过或未通过的所有关键词/uid/pid
|
||||||
|
|
||||||
|
参数:
|
||||||
|
_pass_keyword: 通过列表
|
||||||
|
not_pass_keyword: 未通过列表
|
||||||
|
is_superuser: 是否超级用户
|
||||||
|
|
||||||
|
返回:
|
||||||
|
BuildImage: 数据图片
|
||||||
|
"""
|
||||||
|
_keyword = [
|
||||||
|
x
|
||||||
|
for x in _pass_keyword
|
||||||
|
if not x.startswith("uid:")
|
||||||
|
and not x.startswith("pid:")
|
||||||
|
and not x.startswith("black:")
|
||||||
|
]
|
||||||
|
_uid = [x for x in _pass_keyword if x.startswith("uid:")]
|
||||||
|
_pid = [x for x in _pass_keyword if x.startswith("pid:")]
|
||||||
|
_n_keyword = [
|
||||||
|
x
|
||||||
|
for x in not_pass_keyword
|
||||||
|
if not x.startswith("uid:")
|
||||||
|
and not x.startswith("pid:")
|
||||||
|
and not x.startswith("black:")
|
||||||
|
]
|
||||||
|
_n_uid = [
|
||||||
|
x
|
||||||
|
for x in not_pass_keyword
|
||||||
|
if x.startswith("uid:") and not x.startswith("black:")
|
||||||
|
]
|
||||||
|
_n_pid = [
|
||||||
|
x
|
||||||
|
for x in not_pass_keyword
|
||||||
|
if x.startswith("pid:") and not x.startswith("black:")
|
||||||
|
]
|
||||||
|
img_width = 0
|
||||||
|
img_data = {
|
||||||
|
"_keyword": {"width": 0, "data": _keyword},
|
||||||
|
"_uid": {"width": 0, "data": _uid},
|
||||||
|
"_pid": {"width": 0, "data": _pid},
|
||||||
|
"_n_keyword": {"width": 0, "data": _n_keyword},
|
||||||
|
"_n_uid": {"width": 0, "data": _n_uid},
|
||||||
|
"_n_pid": {"width": 0, "data": _n_pid},
|
||||||
|
}
|
||||||
|
for x in list(img_data.keys()):
|
||||||
|
img_data[x]["width"] = math.ceil(len(img_data[x]["data"]) / 40)
|
||||||
|
img_width += img_data[x]["width"] * 200
|
||||||
|
if not is_superuser:
|
||||||
|
img_width = (
|
||||||
|
img_width
|
||||||
|
- (
|
||||||
|
img_data["_n_keyword"]["width"]
|
||||||
|
+ img_data["_n_uid"]["width"]
|
||||||
|
+ img_data["_n_pid"]["width"]
|
||||||
|
)
|
||||||
|
* 200
|
||||||
|
)
|
||||||
|
del img_data["_n_keyword"]
|
||||||
|
del img_data["_n_pid"]
|
||||||
|
del img_data["_n_uid"]
|
||||||
|
current_width = 0
|
||||||
|
A = BuildImage(img_width, 1100)
|
||||||
|
for x in list(img_data.keys()):
|
||||||
|
if img_data[x]["data"]:
|
||||||
|
# img = BuildImage(img_data[x]["width"] * 200, 1100, 200, 1100, font_size=40)
|
||||||
|
img = BuildImage(img_data[x]["width"] * 200, 1100, font_size=40)
|
||||||
|
start_index = 0
|
||||||
|
end_index = 40
|
||||||
|
total_index = img_data[x]["width"] * 40
|
||||||
|
for _ in range(img_data[x]["width"]):
|
||||||
|
tmp = BuildImage(198, 1100, font_size=20)
|
||||||
|
text_img = BuildImage(198, 100, font_size=50)
|
||||||
|
key_str = "\n".join(
|
||||||
|
[key for key in img_data[x]["data"][start_index:end_index]]
|
||||||
|
)
|
||||||
|
await tmp.text((10, 100), key_str)
|
||||||
|
if x.find("_n") == -1:
|
||||||
|
await text_img.text((24, 24), "已收录")
|
||||||
|
else:
|
||||||
|
await text_img.text((24, 24), "待收录")
|
||||||
|
await tmp.paste(text_img, (0, 0))
|
||||||
|
start_index += 40
|
||||||
|
end_index = (
|
||||||
|
end_index + 40 if end_index + 40 <= total_index else total_index
|
||||||
|
)
|
||||||
|
background_img = BuildImage(200, 1100, color="#FFE4C4")
|
||||||
|
await background_img.paste(tmp, (1, 1))
|
||||||
|
await img.paste(background_img)
|
||||||
|
await A.paste(img, (current_width, 0))
|
||||||
|
current_width += img_data[x]["width"] * 200
|
||||||
|
return A
|
||||||
|
|
||||||
|
|
||||||
|
def _check_black(img_urls: list[str], black: list[str]) -> bool:
|
||||||
|
"""检测pid是否在黑名单中
|
||||||
|
|
||||||
|
参数:
|
||||||
|
img_urls: 图片img列表
|
||||||
|
black: 黑名单
|
||||||
|
|
||||||
|
返回:
|
||||||
|
bool: 是否在黑名单中
|
||||||
|
"""
|
||||||
|
for b in black:
|
||||||
|
for img_url in img_urls:
|
||||||
|
if b in img_url:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
1
zhenxun/plugins/pix_gallery/_model/__init__.py
Normal file
1
zhenxun/plugins/pix_gallery/_model/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
89
zhenxun/plugins/pix_gallery/_model/omega_pixiv_illusts.py
Normal file
89
zhenxun/plugins/pix_gallery/_model/omega_pixiv_illusts.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
from tortoise import fields
|
||||||
|
from tortoise.contrib.postgres.functions import Random
|
||||||
|
|
||||||
|
from zhenxun.services.db_context import Model
|
||||||
|
|
||||||
|
|
||||||
|
class OmegaPixivIllusts(Model):
|
||||||
|
|
||||||
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
|
"""自增id"""
|
||||||
|
pid = fields.BigIntField()
|
||||||
|
"""pid"""
|
||||||
|
uid = fields.BigIntField()
|
||||||
|
"""uid"""
|
||||||
|
title = fields.CharField(255)
|
||||||
|
"""标题"""
|
||||||
|
uname = fields.CharField(255)
|
||||||
|
"""画师名称"""
|
||||||
|
classified = fields.IntField()
|
||||||
|
"""标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取"""
|
||||||
|
nsfw_tag = fields.IntField()
|
||||||
|
"""nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18"""
|
||||||
|
width = fields.IntField()
|
||||||
|
"""宽度"""
|
||||||
|
height = fields.IntField()
|
||||||
|
"""高度"""
|
||||||
|
tags = fields.TextField()
|
||||||
|
"""tags"""
|
||||||
|
url = fields.CharField(255)
|
||||||
|
"""pixiv url链接"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = "omega_pixiv_illusts"
|
||||||
|
table_description = "omega图库数据表"
|
||||||
|
unique_together = ("pid", "url")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def query_images(
|
||||||
|
cls,
|
||||||
|
keywords: list[str] | None = None,
|
||||||
|
uid: int | None = None,
|
||||||
|
pid: int | None = None,
|
||||||
|
nsfw_tag: int | None = 0,
|
||||||
|
num: int = 100,
|
||||||
|
) -> list["OmegaPixivIllusts"]:
|
||||||
|
"""查找符合条件的图片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
keywords: 关键词
|
||||||
|
uid: 画师uid
|
||||||
|
pid: 图片pid
|
||||||
|
nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
|
||||||
|
num: 获取图片数量
|
||||||
|
"""
|
||||||
|
if not num:
|
||||||
|
return []
|
||||||
|
query = cls
|
||||||
|
if nsfw_tag is not None:
|
||||||
|
query = cls.filter(nsfw_tag=nsfw_tag)
|
||||||
|
if keywords:
|
||||||
|
for keyword in keywords:
|
||||||
|
query = query.filter(tags__contains=keyword)
|
||||||
|
elif uid:
|
||||||
|
query = query.filter(uid=uid)
|
||||||
|
elif pid:
|
||||||
|
query = query.filter(pid=pid)
|
||||||
|
query = query.annotate(rand=Random()).limit(num)
|
||||||
|
return await query.all() # type: ignore
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_keyword_num(
|
||||||
|
cls, tags: list[str] | None = None
|
||||||
|
) -> tuple[int, int, int]:
|
||||||
|
"""获取相关关键词(keyword, tag)在图库中的数量
|
||||||
|
|
||||||
|
参数:
|
||||||
|
tags: 关键词/Tag
|
||||||
|
"""
|
||||||
|
query = cls
|
||||||
|
if tags:
|
||||||
|
for tag in tags:
|
||||||
|
query = query.filter(tags__contains=tag)
|
||||||
|
else:
|
||||||
|
query = query.all()
|
||||||
|
count = await query.filter(nsfw_tag=0).count()
|
||||||
|
setu_count = await query.filter(nsfw_tag=1).count()
|
||||||
|
r18_count = await query.filter(nsfw_tag=2).count()
|
||||||
|
return count, setu_count, r18_count
|
||||||
91
zhenxun/plugins/pix_gallery/_model/pixiv.py
Normal file
91
zhenxun/plugins/pix_gallery/_model/pixiv.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
from tortoise import fields
|
||||||
|
from tortoise.contrib.postgres.functions import Random
|
||||||
|
|
||||||
|
from zhenxun.services.db_context import Model
|
||||||
|
|
||||||
|
|
||||||
|
class Pixiv(Model):
|
||||||
|
|
||||||
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
|
"""自增id"""
|
||||||
|
pid = fields.BigIntField()
|
||||||
|
"""pid"""
|
||||||
|
uid = fields.BigIntField()
|
||||||
|
"""uid"""
|
||||||
|
author = fields.CharField(255)
|
||||||
|
"""作者"""
|
||||||
|
title = fields.CharField(255)
|
||||||
|
"""标题"""
|
||||||
|
width = fields.IntField()
|
||||||
|
"""宽度"""
|
||||||
|
height = fields.IntField()
|
||||||
|
"""高度"""
|
||||||
|
view = fields.IntField()
|
||||||
|
"""pixiv查看数"""
|
||||||
|
bookmarks = fields.IntField()
|
||||||
|
"""收藏数"""
|
||||||
|
tags = fields.TextField()
|
||||||
|
"""tags"""
|
||||||
|
img_url = fields.CharField(255)
|
||||||
|
"""pixiv url链接"""
|
||||||
|
img_p = fields.CharField(255)
|
||||||
|
"""图片pN"""
|
||||||
|
is_r18 = fields.BooleanField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = "pixiv"
|
||||||
|
table_description = "pix图库数据表"
|
||||||
|
unique_together = ("pid", "img_url", "img_p")
|
||||||
|
|
||||||
|
# 0:非r18 1:r18 2:混合
|
||||||
|
@classmethod
|
||||||
|
async def query_images(
|
||||||
|
cls,
|
||||||
|
keywords: list[str] | None = None,
|
||||||
|
uid: int | None = None,
|
||||||
|
pid: int | None = None,
|
||||||
|
r18: int | None = 0,
|
||||||
|
num: int = 100,
|
||||||
|
) -> list["Pixiv"]:
|
||||||
|
"""查找符合条件的图片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
keywords: 关键词
|
||||||
|
uid: 画师uid
|
||||||
|
pid: 图片pid
|
||||||
|
r18: 是否r18,0:非r18 1:r18 2:混合
|
||||||
|
num: 查找图片的数量
|
||||||
|
"""
|
||||||
|
if not num:
|
||||||
|
return []
|
||||||
|
query = cls
|
||||||
|
if r18 == 0:
|
||||||
|
query = query.filter(is_r18=False)
|
||||||
|
elif r18 == 1:
|
||||||
|
query = query.filter(is_r18=True)
|
||||||
|
if keywords:
|
||||||
|
for keyword in keywords:
|
||||||
|
query = query.filter(tags__contains=keyword)
|
||||||
|
elif uid:
|
||||||
|
query = query.filter(uid=uid)
|
||||||
|
elif pid:
|
||||||
|
query = query.filter(pid=pid)
|
||||||
|
query = query.annotate(rand=Random()).limit(num)
|
||||||
|
return await query.all() # type: ignore
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_keyword_num(cls, tags: list[str] | None = None) -> tuple[int, int]:
|
||||||
|
"""获取相关关键词(keyword, tag)在图库中的数量
|
||||||
|
|
||||||
|
参数:
|
||||||
|
tags: 关键词/Tag
|
||||||
|
"""
|
||||||
|
query = cls
|
||||||
|
if tags:
|
||||||
|
for tag in tags:
|
||||||
|
query = query.filter(tags__contains=tag)
|
||||||
|
else:
|
||||||
|
query = query.all()
|
||||||
|
count = await query.filter(is_r18=False).count()
|
||||||
|
r18_count = await query.filter(is_r18=True).count()
|
||||||
|
return count, r18_count
|
||||||
52
zhenxun/plugins/pix_gallery/_model/pixiv_keyword_user.py
Normal file
52
zhenxun/plugins/pix_gallery/_model/pixiv_keyword_user.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from tortoise import fields
|
||||||
|
|
||||||
|
from zhenxun.services.db_context import Model
|
||||||
|
|
||||||
|
|
||||||
|
class PixivKeywordUser(Model):
|
||||||
|
|
||||||
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
|
"""自增id"""
|
||||||
|
user_id = fields.CharField(255)
|
||||||
|
"""用户id"""
|
||||||
|
group_id = fields.CharField(255)
|
||||||
|
"""群聊id"""
|
||||||
|
keyword = fields.CharField(255, unique=True)
|
||||||
|
"""关键词"""
|
||||||
|
is_pass = fields.BooleanField()
|
||||||
|
"""是否通过"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = "pixiv_keyword_users"
|
||||||
|
table_description = "pixiv关键词数据表"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_current_keyword(cls) -> tuple[list[str], list[str]]:
|
||||||
|
"""获取当前通过与未通过的关键词"""
|
||||||
|
pass_keyword = []
|
||||||
|
not_pass_keyword = []
|
||||||
|
for data in await cls.all().values_list("keyword", "is_pass"):
|
||||||
|
if data[1]:
|
||||||
|
pass_keyword.append(data[0])
|
||||||
|
else:
|
||||||
|
not_pass_keyword.append(data[0])
|
||||||
|
return pass_keyword, not_pass_keyword
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_black_pid(cls) -> list[str]:
|
||||||
|
"""获取黑名单PID"""
|
||||||
|
black_pid = []
|
||||||
|
keyword_list = await cls.filter(user_id="114514").values_list(
|
||||||
|
"keyword", flat=True
|
||||||
|
)
|
||||||
|
for image in keyword_list:
|
||||||
|
black_pid.append(image[6:])
|
||||||
|
return black_pid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def _run_script(cls):
|
||||||
|
return [
|
||||||
|
"ALTER TABLE pixiv_keyword_users RENAME COLUMN user_qq TO user_id;", # 将user_qq改为user_id
|
||||||
|
"ALTER TABLE pixiv_keyword_users ALTER COLUMN user_id TYPE character varying(255);",
|
||||||
|
"ALTER TABLE pixiv_keyword_users ALTER COLUMN group_id TYPE character varying(255);",
|
||||||
|
]
|
||||||
251
zhenxun/plugins/pix_gallery/pix.py
Normal file
251
zhenxun/plugins/pix_gallery/pix.py
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
from nonebot.adapters import Bot
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import (
|
||||||
|
Alconna,
|
||||||
|
Args,
|
||||||
|
Arparma,
|
||||||
|
Match,
|
||||||
|
Option,
|
||||||
|
on_alconna,
|
||||||
|
store_true,
|
||||||
|
)
|
||||||
|
from nonebot_plugin_saa import Image, MessageFactory, Text
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
|
from zhenxun.configs.utils import BaseBlock, PluginExtraData, RegisterConfig
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.platform import PlatformUtils
|
||||||
|
from zhenxun.utils.withdraw_manage import WithdrawManager
|
||||||
|
|
||||||
|
from ._data_source import get_image
|
||||||
|
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
|
||||||
|
from ._model.pixiv import Pixiv
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="PIX",
|
||||||
|
description="这里是PIX图库!",
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
|
||||||
|
pid [uid]: 通过uid获取图片
|
||||||
|
pix pid[pid]: 查看图库中指定pid图片
|
||||||
|
示例:pix 萝莉 白丝
|
||||||
|
示例:pix 萝莉 白丝 10 (10为数量)
|
||||||
|
示例:pix #02 (当tag只有1个tag且为数字时,使用#标记,否则将被判定为数量)
|
||||||
|
示例:pix 34582394 (查询指定uid图片)
|
||||||
|
示例:pix pid:12323423 (查询指定pid图片)
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier",
|
||||||
|
version="0.1",
|
||||||
|
superuser_help="""
|
||||||
|
指令:
|
||||||
|
pix -s ?*[tags]: 通过tag获取色图,不含tag时随机
|
||||||
|
pix -r ?*[tags]: 通过tag获取r18图,不含tag时随机
|
||||||
|
""",
|
||||||
|
menu_type="来点好康的",
|
||||||
|
limits=[BaseBlock(result="您有PIX图片正在处理,请稍等...")],
|
||||||
|
configs=[
|
||||||
|
RegisterConfig(
|
||||||
|
key="MAX_ONCE_NUM2FORWARD",
|
||||||
|
value=None,
|
||||||
|
help="单次发送的图片数量达到指定值时转发为合并消息",
|
||||||
|
default_value=None,
|
||||||
|
type=int,
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="ALLOW_GROUP_SETU",
|
||||||
|
value=False,
|
||||||
|
help="允许非超级用户使用-s参数",
|
||||||
|
default_value=False,
|
||||||
|
type=bool,
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="ALLOW_GROUP_R18",
|
||||||
|
value=False,
|
||||||
|
help="允许非超级用户使用-r参数",
|
||||||
|
default_value=False,
|
||||||
|
type=bool,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# pix = on_command("pix", aliases={"PIX", "Pix"}, priority=5, block=True)
|
||||||
|
|
||||||
|
_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"pix",
|
||||||
|
Args["tags?", list[str]],
|
||||||
|
Option("-s", action=store_true, help_text="色图"),
|
||||||
|
Option("-r", action=store_true, help_text="r18"),
|
||||||
|
),
|
||||||
|
priority=5,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
PIX_RATIO = None
|
||||||
|
OMEGA_RATIO = None
|
||||||
|
|
||||||
|
|
||||||
|
@_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, arparma: Arparma, tags: Match[list[str]]):
|
||||||
|
global PIX_RATIO, OMEGA_RATIO
|
||||||
|
gid = session.id3 or session.id2
|
||||||
|
if not session.id1:
|
||||||
|
await Text("用户id为空...").finish()
|
||||||
|
if PIX_RATIO is None:
|
||||||
|
pix_omega_pixiv_ratio = Config.get_config("pix", "PIX_OMEGA_PIXIV_RATIO")
|
||||||
|
PIX_RATIO = pix_omega_pixiv_ratio[0] / (
|
||||||
|
pix_omega_pixiv_ratio[0] + pix_omega_pixiv_ratio[1]
|
||||||
|
)
|
||||||
|
OMEGA_RATIO = 1 - PIX_RATIO
|
||||||
|
num = 1
|
||||||
|
# keyword = arg.extract_plain_text().strip()
|
||||||
|
keyword = ""
|
||||||
|
spt = tags.result if tags.available else []
|
||||||
|
if arparma.find("s"):
|
||||||
|
nsfw_tag = 1
|
||||||
|
elif arparma.find("r"):
|
||||||
|
nsfw_tag = 2
|
||||||
|
else:
|
||||||
|
nsfw_tag = 0
|
||||||
|
if session.id1 not in bot.config.superusers:
|
||||||
|
if (nsfw_tag == 1 and not Config.get_config("pix", "ALLOW_GROUP_SETU")) or (
|
||||||
|
nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
|
||||||
|
):
|
||||||
|
await Text("你不能看这些噢,这些都是是留给管理员看的...").finish()
|
||||||
|
if (n := len(spt)) == 1:
|
||||||
|
if str(spt[0]).isdigit() and int(spt[0]) < 100:
|
||||||
|
num = int(spt[0])
|
||||||
|
keyword = ""
|
||||||
|
elif spt[0].startswith("#"):
|
||||||
|
keyword = spt[0][1:]
|
||||||
|
elif n > 1:
|
||||||
|
if str(spt[-1]).isdigit():
|
||||||
|
num = int(spt[-1])
|
||||||
|
if num > 10:
|
||||||
|
if session.id1 not in bot.config.superusers or (
|
||||||
|
session.id1 in bot.config.superusers and num > 30
|
||||||
|
):
|
||||||
|
num = random.randint(1, 10)
|
||||||
|
await Text(f"太贪心了,就给你发 {num}张 好了").send()
|
||||||
|
spt = spt[:-1]
|
||||||
|
keyword = " ".join(spt)
|
||||||
|
pix_num = int(num * PIX_RATIO) + 15 if PIX_RATIO != 0 else 0
|
||||||
|
omega_num = num - pix_num + 15
|
||||||
|
if str(keyword).isdigit():
|
||||||
|
if num == 1:
|
||||||
|
pix_num = 15
|
||||||
|
omega_num = 15
|
||||||
|
all_image = await Pixiv.query_images(
|
||||||
|
uid=int(keyword), num=pix_num, r18=1 if nsfw_tag == 2 else 0
|
||||||
|
) + await OmegaPixivIllusts.query_images(
|
||||||
|
uid=int(keyword), num=omega_num, nsfw_tag=nsfw_tag
|
||||||
|
)
|
||||||
|
elif keyword.lower().startswith("pid"):
|
||||||
|
pid = keyword.replace("pid", "").replace(":", "").replace(":", "")
|
||||||
|
if not str(pid).isdigit():
|
||||||
|
await Text("PID必须是数字...").finish(reply=True)
|
||||||
|
all_image = await Pixiv.query_images(
|
||||||
|
pid=int(pid), r18=1 if nsfw_tag == 2 else 0
|
||||||
|
)
|
||||||
|
if not all_image:
|
||||||
|
all_image = await OmegaPixivIllusts.query_images(
|
||||||
|
pid=int(pid), nsfw_tag=nsfw_tag
|
||||||
|
)
|
||||||
|
num = len(all_image)
|
||||||
|
else:
|
||||||
|
tmp = await Pixiv.query_images(
|
||||||
|
spt, r18=1 if nsfw_tag == 2 else 0, num=pix_num
|
||||||
|
) + await OmegaPixivIllusts.query_images(spt, nsfw_tag=nsfw_tag, num=omega_num)
|
||||||
|
tmp_ = []
|
||||||
|
all_image = []
|
||||||
|
for x in tmp:
|
||||||
|
if x.pid not in tmp_:
|
||||||
|
all_image.append(x)
|
||||||
|
tmp_.append(x.pid)
|
||||||
|
if not all_image:
|
||||||
|
await Text(f"未在图库中找到与 {keyword} 相关Tag/UID/PID的图片...").finish(
|
||||||
|
reply=True
|
||||||
|
)
|
||||||
|
msg_list = []
|
||||||
|
for _ in range(num):
|
||||||
|
img_url = None
|
||||||
|
author = None
|
||||||
|
if not all_image:
|
||||||
|
await Text("坏了...发完了,没图了...").finish()
|
||||||
|
img = random.choice(all_image)
|
||||||
|
all_image.remove(img) # type: ignore
|
||||||
|
if isinstance(img, OmegaPixivIllusts):
|
||||||
|
img_url = img.url
|
||||||
|
author = img.uname
|
||||||
|
elif isinstance(img, Pixiv):
|
||||||
|
img_url = img.img_url
|
||||||
|
author = img.author
|
||||||
|
pid = img.pid
|
||||||
|
title = img.title
|
||||||
|
uid = img.uid
|
||||||
|
if img_url:
|
||||||
|
_img = await get_image(img_url, session.id1)
|
||||||
|
if _img:
|
||||||
|
if Config.get_config("pix", "SHOW_INFO"):
|
||||||
|
msg_list.append(
|
||||||
|
MessageFactory(
|
||||||
|
[
|
||||||
|
Text(
|
||||||
|
f"title:{title}\n"
|
||||||
|
f"author:{author}\n"
|
||||||
|
f"PID:{pid}\nUID:{uid}\n"
|
||||||
|
),
|
||||||
|
Image(_img),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
msg_list.append(Image(_img))
|
||||||
|
logger.info(
|
||||||
|
f" 查看PIX图库PID: {pid}", arparma.header_result, session=session
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
msg_list.append(Text("这张图似乎下载失败了"))
|
||||||
|
logger.info(
|
||||||
|
f" 查看PIX图库PID: {pid},下载图片出错",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
Config.get_config("pix", "MAX_ONCE_NUM2FORWARD")
|
||||||
|
and num >= Config.get_config("pix", "MAX_ONCE_NUM2FORWARD")
|
||||||
|
and gid
|
||||||
|
):
|
||||||
|
for msg in msg_list:
|
||||||
|
# receipt = await PlatformUtils.send_message(
|
||||||
|
# bot, None, group_id=gid, message=msg
|
||||||
|
# )
|
||||||
|
receipt = await msg.send()
|
||||||
|
if receipt:
|
||||||
|
message_id = receipt.extract_message_id().message_id
|
||||||
|
await WithdrawManager.withdraw_message(
|
||||||
|
bot,
|
||||||
|
str(message_id),
|
||||||
|
Config.get_config("pix", "WITHDRAW_PIX_MESSAGE"),
|
||||||
|
session,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for msg in msg_list:
|
||||||
|
receipt = await msg.send()
|
||||||
|
# receipt = await PlatformUtils.send_message(
|
||||||
|
# bot, session.id1, group_id=gid, message=msg
|
||||||
|
# )
|
||||||
|
if receipt:
|
||||||
|
message_id = receipt.extract_message_id().message_id
|
||||||
|
await WithdrawManager.withdraw_message(
|
||||||
|
bot,
|
||||||
|
message_id,
|
||||||
|
Config.get_config("pix", "WITHDRAW_PIX_MESSAGE"),
|
||||||
|
session,
|
||||||
|
)
|
||||||
129
zhenxun/plugins/pix_gallery/pix_add_keyword.py
Normal file
129
zhenxun/plugins/pix_gallery/pix_add_keyword.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
from nonebot.adapters import Bot
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import (
|
||||||
|
Alconna,
|
||||||
|
Args,
|
||||||
|
Arparma,
|
||||||
|
Option,
|
||||||
|
on_alconna,
|
||||||
|
store_true,
|
||||||
|
)
|
||||||
|
from nonebot_plugin_saa import Text
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
|
from ._data_source import uid_pid_exists
|
||||||
|
from ._model.pixiv import Pixiv
|
||||||
|
from ._model.pixiv_keyword_user import PixivKeywordUser
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="PIX添加",
|
||||||
|
description="PIX关键词/UID/PID添加管理",
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
添加pix关键词 [Tag]: 添加一个pix搜索收录Tag
|
||||||
|
pix添加 uid [uid]: 添加一个pix搜索收录uid
|
||||||
|
pix添加 pid [pid]: 添加一个pix收录pid
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier",
|
||||||
|
version="0.1",
|
||||||
|
).dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
_add_matcher = on_alconna(
|
||||||
|
Alconna("添加pix关键词", Args["keyword", str]), priority=5, block=True
|
||||||
|
)
|
||||||
|
|
||||||
|
_uid_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"pix添加",
|
||||||
|
Args["add_type", ["uid", "pid"]]["id", str],
|
||||||
|
Option("-f", action=store_true, help_text="强制收录不检查是否存在"),
|
||||||
|
),
|
||||||
|
priority=5,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_black_matcher = on_alconna(
|
||||||
|
Alconna("添加pix黑名单", Args["pid", str]), priority=5, block=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_add_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, keyword: str, arparma: Arparma):
|
||||||
|
group_id = session.id3 or session.id2 or -1
|
||||||
|
if not await PixivKeywordUser.exists(keyword=keyword):
|
||||||
|
await PixivKeywordUser.create(
|
||||||
|
user_id=str(session.id1),
|
||||||
|
group_id=str(group_id),
|
||||||
|
keyword=keyword,
|
||||||
|
is_pass=str(session.id1) in bot.config.superusers,
|
||||||
|
)
|
||||||
|
text = f"已成功添加pixiv搜图关键词:{keyword}"
|
||||||
|
if session.id1 not in bot.config.superusers:
|
||||||
|
text += ",请等待管理员通过该关键词!"
|
||||||
|
await Text(text).send(reply=True)
|
||||||
|
logger.info(
|
||||||
|
f"添加了pixiv搜图关键词: {keyword}", arparma.header_result, session=session
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await Text(f"该关键词 {keyword} 已存在...").send()
|
||||||
|
|
||||||
|
|
||||||
|
@_uid_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, arparma: Arparma, add_type: str, id: str):
|
||||||
|
group_id = session.id3 or session.id2 or -1
|
||||||
|
exists_flag = True
|
||||||
|
if arparma.find("f") and session.id1 in bot.config.superusers:
|
||||||
|
exists_flag = False
|
||||||
|
word = None
|
||||||
|
if add_type == "uid":
|
||||||
|
word = f"uid:{id}"
|
||||||
|
else:
|
||||||
|
word = f"pid:{id}"
|
||||||
|
if await Pixiv.get_or_none(pid=int(id), img_p="p0"):
|
||||||
|
await Text(f"该PID:{id}已存在...").finish(reply=True)
|
||||||
|
if not await uid_pid_exists(word) and exists_flag:
|
||||||
|
await Text("画师或作品不存在或搜索正在CD,请稍等...").finish(reply=True)
|
||||||
|
if not await PixivKeywordUser.exists(keyword=word):
|
||||||
|
await PixivKeywordUser.create(
|
||||||
|
user_id=session.id1,
|
||||||
|
group_id=str(group_id),
|
||||||
|
keyword=word,
|
||||||
|
is_pass=session.id1 in bot.config.superusers,
|
||||||
|
)
|
||||||
|
text = f"已成功添加pixiv搜图UID/PID:{id}"
|
||||||
|
if session.id1 not in bot.config.superusers:
|
||||||
|
text += ",请等待管理员通过该关键词!"
|
||||||
|
await Text(text).send(reply=True)
|
||||||
|
else:
|
||||||
|
await Text(f"该UID/PID:{id} 已存在...").send()
|
||||||
|
|
||||||
|
|
||||||
|
@_black_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, arparma: Arparma, pid: str):
|
||||||
|
img_p = ""
|
||||||
|
if "p" in pid:
|
||||||
|
img_p = pid.split("p")[-1]
|
||||||
|
pid = pid.replace("_", "")
|
||||||
|
pid = pid[: pid.find("p")]
|
||||||
|
if not pid.isdigit:
|
||||||
|
await Text("PID必须全部是数字!").finish(reply=True)
|
||||||
|
if not await PixivKeywordUser.exists(
|
||||||
|
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}"
|
||||||
|
):
|
||||||
|
await PixivKeywordUser.create(
|
||||||
|
user_id=114514,
|
||||||
|
group_id=114514,
|
||||||
|
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}",
|
||||||
|
is_pass=session.id1 in bot.config.superusers,
|
||||||
|
)
|
||||||
|
await Text(f"已添加PID:{pid} 至黑名单中...").send()
|
||||||
|
logger.info(
|
||||||
|
f" 添加了pixiv搜图黑名单 PID:{pid}", arparma.header_result, session=session
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await Text(f"PID:{pid} 已添加黑名单中,添加失败...").send()
|
||||||
217
zhenxun/plugins/pix_gallery/pix_pass_del_keyword.py
Normal file
217
zhenxun/plugins/pix_gallery/pix_pass_del_keyword.py
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
from nonebot.adapters import Bot
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import (
|
||||||
|
Alconna,
|
||||||
|
Args,
|
||||||
|
Arparma,
|
||||||
|
Match,
|
||||||
|
Option,
|
||||||
|
on_alconna,
|
||||||
|
store_true,
|
||||||
|
)
|
||||||
|
from nonebot_plugin_saa import Mention, MessageFactory, Text
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.enum import PluginType
|
||||||
|
from zhenxun.utils.platform import PlatformUtils
|
||||||
|
|
||||||
|
from ._data_source import remove_image
|
||||||
|
from ._model.pixiv import Pixiv
|
||||||
|
from ._model.pixiv_keyword_user import PixivKeywordUser
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="PIX删除",
|
||||||
|
description="PIX关键词/UID/PID添加管理",
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
pix关键词 [y/n] [关键词/pid/uid]
|
||||||
|
删除pix关键词 ['pid'/'uid'/'keyword'] [关键词/pid/uid]
|
||||||
|
删除pix图片 *[pid]
|
||||||
|
示例:pix关键词 y 萝莉
|
||||||
|
示例:pix关键词 y 12312312 uid
|
||||||
|
示例:pix关键词 n 12312312 pid
|
||||||
|
示例:删除pix关键词 keyword 萝莉
|
||||||
|
示例:删除pix关键词 uid 123123123
|
||||||
|
示例:删除pix关键词 pid 123123
|
||||||
|
示例:删除pix图片 4223442
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier", version="0.1", plugin_type=PluginType.SUPERUSER
|
||||||
|
).dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_pass_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"pix关键词", Args["status", ["y", "n"]]["keyword", str]["type?", ["uid", "pid"]]
|
||||||
|
),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
priority=1,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_del_matcher = on_alconna(
|
||||||
|
Alconna("删除pix关键词", Args["type", ["pid", "uid", "keyword"]]["keyword", str]),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
priority=1,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_del_pic_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"删除pix图片",
|
||||||
|
Args["pid", str],
|
||||||
|
Option("-b|--black", action=store_true, help_text=""),
|
||||||
|
),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
priority=1,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_pass_matcher.handle()
|
||||||
|
async def _(
|
||||||
|
bot: Bot,
|
||||||
|
session: EventSession,
|
||||||
|
arparma: Arparma,
|
||||||
|
status: str,
|
||||||
|
keyword: str,
|
||||||
|
type: Match[str],
|
||||||
|
):
|
||||||
|
tmp = {"group": {}, "private": {}}
|
||||||
|
flag = status == "y"
|
||||||
|
if type.available:
|
||||||
|
if type.result == "uid":
|
||||||
|
keyword = f"uid:{keyword}"
|
||||||
|
else:
|
||||||
|
keyword = f"pid:{keyword}"
|
||||||
|
if not keyword[4:].isdigit():
|
||||||
|
await Text(f"{keyword} 非全数字...").finish(reply=True)
|
||||||
|
data = await PixivKeywordUser.get_or_none(keyword=keyword)
|
||||||
|
user_id = 0
|
||||||
|
group_id = 0
|
||||||
|
if data:
|
||||||
|
data.is_pass = flag
|
||||||
|
await data.save(update_fields=["is_pass"])
|
||||||
|
user_id, group_id = data.user_id, data.group_id
|
||||||
|
if not user_id:
|
||||||
|
await Text(f"未找到关键词/UID:{keyword},请检查关键词/UID是否存在...").finish(
|
||||||
|
reply=True
|
||||||
|
)
|
||||||
|
if flag:
|
||||||
|
if group_id == -1:
|
||||||
|
if not tmp["private"].get(user_id):
|
||||||
|
tmp["private"][user_id] = {"keyword": [keyword]}
|
||||||
|
else:
|
||||||
|
tmp["private"][user_id]["keyword"].append(keyword)
|
||||||
|
else:
|
||||||
|
if not tmp["group"].get(group_id):
|
||||||
|
tmp["group"][group_id] = {}
|
||||||
|
if not tmp["group"][group_id].get(user_id):
|
||||||
|
tmp["group"][group_id][user_id] = {"keyword": [keyword]}
|
||||||
|
else:
|
||||||
|
tmp["group"][group_id][user_id]["keyword"].append(keyword)
|
||||||
|
await Text(f"已成功{'通过' if flag else '拒绝'}搜图关键词:{keyword}...").send()
|
||||||
|
for user in tmp["private"]:
|
||||||
|
text = ",".join(tmp["private"][user]["keyword"])
|
||||||
|
await PlatformUtils.send_message(
|
||||||
|
bot,
|
||||||
|
user,
|
||||||
|
None,
|
||||||
|
f"你的关键词/UID/PID {text} 已被管理员通过,将在下一次进行更新...",
|
||||||
|
)
|
||||||
|
# await bot.send_private_msg(
|
||||||
|
# user_id=user,
|
||||||
|
# message=f"你的关键词/UID/PID {x} 已被管理员通过,将在下一次进行更新...",
|
||||||
|
# )
|
||||||
|
for group in tmp["group"]:
|
||||||
|
for user in tmp["group"][group]:
|
||||||
|
text = ",".join(tmp["group"][group][user]["keyword"])
|
||||||
|
await PlatformUtils.send_message(
|
||||||
|
bot,
|
||||||
|
None,
|
||||||
|
group_id=group,
|
||||||
|
message=MessageFactory(
|
||||||
|
[
|
||||||
|
Mention(user_id=user),
|
||||||
|
Text(
|
||||||
|
"你的关键词/UID/PID {x} 已被管理员通过,将在下一次进行更新..."
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# await bot.send_group_msg(
|
||||||
|
# group_id=group,
|
||||||
|
# message=Message(
|
||||||
|
# f"{at(user)}你的关键词/UID/PID {x} 已被管理员通过,将在下一次进行更新..."
|
||||||
|
# ),
|
||||||
|
# )
|
||||||
|
logger.info(
|
||||||
|
f" 通过了pixiv搜图关键词/UID: {keyword}", arparma.header_result, session=session
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_del_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, arparma: Arparma, type: str, keyword: str):
|
||||||
|
if type != "keyword":
|
||||||
|
keyword = f"{type}:{keyword}"
|
||||||
|
if data := await PixivKeywordUser.get_or_none(keyword=keyword):
|
||||||
|
await data.delete()
|
||||||
|
await Text(f"删除搜图关键词/UID:{keyword} 成功...").send()
|
||||||
|
logger.info(
|
||||||
|
f" 删除了pixiv搜图关键词: {keyword}", arparma.header_result, session=session
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await Text(f"未查询到搜索关键词/UID/PID:{keyword},删除失败!").send()
|
||||||
|
|
||||||
|
|
||||||
|
@_del_pic_matcher.handle()
|
||||||
|
async def _(bot: Bot, session: EventSession, arparma: Arparma, keyword: str):
|
||||||
|
msg = ""
|
||||||
|
black_pid = ""
|
||||||
|
flag = arparma.find("black")
|
||||||
|
img_p = None
|
||||||
|
if "p" in keyword:
|
||||||
|
img_p = keyword.split("p")[-1]
|
||||||
|
keyword = keyword.replace("_", "")
|
||||||
|
keyword = keyword[: keyword.find("p")]
|
||||||
|
elif "ugoira" in keyword:
|
||||||
|
img_p = keyword.split("ugoira")[-1]
|
||||||
|
keyword = keyword.replace("_", "")
|
||||||
|
keyword = keyword[: keyword.find("ugoira")]
|
||||||
|
if keyword.isdigit():
|
||||||
|
if await Pixiv.query_images(pid=int(keyword), r18=2):
|
||||||
|
if await remove_image(int(keyword), img_p):
|
||||||
|
msg += f'{keyword}{f"_p{img_p}" if img_p else ""},'
|
||||||
|
if flag:
|
||||||
|
if await PixivKeywordUser.exists(
|
||||||
|
keyword=f"black:{keyword}{f'_p{img_p}' if img_p else ''}"
|
||||||
|
):
|
||||||
|
await PixivKeywordUser.create(
|
||||||
|
user_id="114514",
|
||||||
|
group_id="114514",
|
||||||
|
keyword=f"black:{keyword}{f'_p{img_p}' if img_p else ''}",
|
||||||
|
is_pass=False,
|
||||||
|
)
|
||||||
|
black_pid += f'{keyword}{f"_p{img_p}" if img_p else ""},'
|
||||||
|
logger.info(
|
||||||
|
f" 删除了PIX图片 PID:{keyword}{f'_p{img_p}' if img_p else ''}",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
# else:
|
||||||
|
# await del_pic.send(
|
||||||
|
# f"PIX:删除pid:{pid}{f'_p{img_p}' if img_p else ''} 失败.."
|
||||||
|
# )
|
||||||
|
else:
|
||||||
|
await Text(
|
||||||
|
f"PIX:图片pix:{keyword}{f'_p{img_p}' if img_p else ''} 不存在...无法删除.."
|
||||||
|
).send()
|
||||||
|
else:
|
||||||
|
await Text(f"PID必须为数字!pid:{keyword}").send(reply=True)
|
||||||
|
await Text(f"PIX:成功删除图片:{msg[:-1]}").send()
|
||||||
|
if flag:
|
||||||
|
await Text(f"成功图片PID加入黑名单:{black_pid[:-1]}").send()
|
||||||
81
zhenxun/plugins/pix_gallery/pix_show_info.py
Normal file
81
zhenxun/plugins/pix_gallery/pix_show_info.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
from nonebot.adapters import Bot
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import Alconna, Args, Arparma, Match, on_alconna
|
||||||
|
from nonebot_plugin_saa import Image, Text
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
|
from ._data_source import gen_keyword_pic, get_keyword_num
|
||||||
|
from ._model.pixiv_keyword_user import PixivKeywordUser
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="查看pix图库",
|
||||||
|
description="让我看看管理员私藏了多少货",
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
我的pix关键词
|
||||||
|
显示pix关键词
|
||||||
|
查看pix图库 ?[tag]: 查看指定tag图片数量,为空时查看整个图库
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier",
|
||||||
|
version="0.1",
|
||||||
|
).dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
_my_matcher = on_alconna(Alconna("我的pix关键词"), priority=5, block=True)
|
||||||
|
|
||||||
|
_show_matcher = on_alconna(Alconna("显示pix关键词"), priority=5, block=True)
|
||||||
|
|
||||||
|
_pix_matcher = on_alconna(
|
||||||
|
Alconna("查看pix图库", Args["keyword?", str]), priority=5, block=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_my_matcher.handle()
|
||||||
|
async def _(arparma: Arparma, session: EventSession):
|
||||||
|
data = await PixivKeywordUser.filter(user_id=session.id1).values_list(
|
||||||
|
"keyword", flat=True
|
||||||
|
)
|
||||||
|
if not data:
|
||||||
|
await Text("您目前没有提供任何Pixiv搜图关键字...").finish(reply=True)
|
||||||
|
await Text(f"您目前提供的如下关键字:\n\t" + ",".join(data)).send() # type: ignore
|
||||||
|
logger.info("查看我的pix关键词", arparma.header_result, session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@_show_matcher.handle()
|
||||||
|
async def _(bot: Bot, arparma: Arparma, session: EventSession):
|
||||||
|
_pass_keyword, not_pass_keyword = await PixivKeywordUser.get_current_keyword()
|
||||||
|
if _pass_keyword or not_pass_keyword:
|
||||||
|
image = await gen_keyword_pic(
|
||||||
|
_pass_keyword, not_pass_keyword, session.id1 in bot.config.superusers
|
||||||
|
)
|
||||||
|
await Image(image.pic2bytes()).send() # type: ignore
|
||||||
|
else:
|
||||||
|
if session.id1 in bot.config.superusers:
|
||||||
|
await Text(f"目前没有已收录或待收录的搜索关键词...").send()
|
||||||
|
else:
|
||||||
|
await Text(f"目前没有已收录的搜索关键词...").send()
|
||||||
|
|
||||||
|
|
||||||
|
@_pix_matcher.handle()
|
||||||
|
async def _(bot: Bot, arparma: Arparma, session: EventSession, keyword: Match[str]):
|
||||||
|
_keyword = ""
|
||||||
|
if keyword.available:
|
||||||
|
_keyword = keyword.result
|
||||||
|
count, r18_count, count_, setu_count, r18_count_ = await get_keyword_num(_keyword)
|
||||||
|
await Text(
|
||||||
|
f"PIX图库:{_keyword}\n"
|
||||||
|
f"总数:{count + r18_count}\n"
|
||||||
|
f"美图:{count}\n"
|
||||||
|
f"R18:{r18_count}\n"
|
||||||
|
f"---------------\n"
|
||||||
|
f"Omega图库:{_keyword}\n"
|
||||||
|
f"总数:{count_ + setu_count + r18_count_}\n"
|
||||||
|
f"美图:{count_}\n"
|
||||||
|
f"色图:{setu_count}\n"
|
||||||
|
f"R18:{r18_count_}"
|
||||||
|
).send()
|
||||||
|
logger.info("查看pix图库", arparma.header_result, session=session)
|
||||||
221
zhenxun/plugins/pix_gallery/pix_update.py
Normal file
221
zhenxun/plugins/pix_gallery/pix_update.py
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from nonebot.adapters import Bot
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import (
|
||||||
|
Alconna,
|
||||||
|
Args,
|
||||||
|
Arparma,
|
||||||
|
Match,
|
||||||
|
Option,
|
||||||
|
on_alconna,
|
||||||
|
store_true,
|
||||||
|
)
|
||||||
|
from nonebot_plugin_saa import Text
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.enum import PluginType
|
||||||
|
|
||||||
|
from ._data_source import start_update_image_url
|
||||||
|
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
|
||||||
|
from ._model.pixiv import Pixiv
|
||||||
|
from ._model.pixiv_keyword_user import PixivKeywordUser
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="pix检查更新",
|
||||||
|
description="pix图库收录数据检查更新",
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
更新pix关键词 *[keyword/uid/pid] [num=max]: 更新仅keyword/uid/pid或全部
|
||||||
|
pix检测更新:检测从未更新过的uid和pid
|
||||||
|
示例:更新pix关键词keyword
|
||||||
|
示例:更新pix关键词uid 10
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier", version="0.1", plugin_type=PluginType.SUPERUSER
|
||||||
|
).dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_update_matcher = on_alconna(
|
||||||
|
Alconna("更新pix关键词", Args["type", ["uid", "pid", "keyword"]]["num?", int]),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
priority=1,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_check_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"pix检测更新", Option("-u|--update", action=store_true, help_text="是否更新")
|
||||||
|
),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
priority=1,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_omega_matcher = on_alconna(
|
||||||
|
Alconna("检测omega图库"), permission=SUPERUSER, priority=1, block=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_update_matcher.handle()
|
||||||
|
async def _(arparma: Arparma, session: EventSession, type: str, num: Match[int]):
|
||||||
|
_pass_keyword, _ = await PixivKeywordUser.get_current_keyword()
|
||||||
|
_pass_keyword.reverse()
|
||||||
|
black_pid = await PixivKeywordUser.get_black_pid()
|
||||||
|
_keyword = [
|
||||||
|
x
|
||||||
|
for x in _pass_keyword
|
||||||
|
if not x.startswith("uid:")
|
||||||
|
and not x.startswith("pid:")
|
||||||
|
and not x.startswith("black:")
|
||||||
|
]
|
||||||
|
_uid = [x for x in _pass_keyword if x.startswith("uid:")]
|
||||||
|
_pid = [x for x in _pass_keyword if x.startswith("pid:")]
|
||||||
|
_num = num.result if num.available else 9999
|
||||||
|
if _num < 10000:
|
||||||
|
keyword_str = ",".join(
|
||||||
|
_keyword[: _num if _num < len(_keyword) else len(_keyword)]
|
||||||
|
)
|
||||||
|
uid_str = ",".join(_uid[: _num if _num < len(_uid) else len(_uid)])
|
||||||
|
pid_str = ",".join(_pid[: _num if _num < len(_pid) else len(_pid)])
|
||||||
|
if type == "pid":
|
||||||
|
update_lst = _pid
|
||||||
|
info = f"开始更新Pixiv搜图PID:\n{pid_str}"
|
||||||
|
elif type == "uid":
|
||||||
|
update_lst = _uid
|
||||||
|
info = f"开始更新Pixiv搜图UID:\n{uid_str}"
|
||||||
|
elif type == "keyword":
|
||||||
|
update_lst = _keyword
|
||||||
|
info = f"开始更新Pixiv搜图关键词:\n{keyword_str}"
|
||||||
|
else:
|
||||||
|
update_lst = _pass_keyword
|
||||||
|
info = f"开始更新Pixiv搜图关键词:\n{keyword_str}\n更新UID:{uid_str}\n更新PID:{pid_str}"
|
||||||
|
_num = _num if _num < len(update_lst) else len(update_lst)
|
||||||
|
else:
|
||||||
|
if type == "pid":
|
||||||
|
update_lst = [f"pid:{_num}"]
|
||||||
|
info = f"开始更新Pixiv搜图UID:\npid:{_num}"
|
||||||
|
else:
|
||||||
|
update_lst = [f"uid:{_num}"]
|
||||||
|
info = f"开始更新Pixiv搜图UID:\nuid:{_num}"
|
||||||
|
await Text(info).send()
|
||||||
|
start_time = time.time()
|
||||||
|
pid_count, pic_count = await start_update_image_url(update_lst[:_num], black_pid, type == 'pid')
|
||||||
|
await Text(
|
||||||
|
f"Pixiv搜图关键词搜图更新完成...\n"
|
||||||
|
f"累计更新PID {pid_count} 个\n"
|
||||||
|
f"累计更新图片 {pic_count} 张"
|
||||||
|
+ "\n耗时:{:.2f}秒".format((time.time() - start_time))
|
||||||
|
).send()
|
||||||
|
logger.info("更新pix关键词", arparma.header_result, session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@_check_matcher.handle()
|
||||||
|
async def _(bot: Bot, arparma: Arparma, session: EventSession):
|
||||||
|
_pass_keyword, _ = await PixivKeywordUser.get_current_keyword()
|
||||||
|
x_uid = []
|
||||||
|
x_pid = []
|
||||||
|
_uid = [int(x[4:]) for x in _pass_keyword if x.startswith("uid:")]
|
||||||
|
_pid = [int(x[4:]) for x in _pass_keyword if x.startswith("pid:")]
|
||||||
|
all_images = await Pixiv.query_images(r18=2)
|
||||||
|
for img in all_images:
|
||||||
|
if img.pid not in x_pid:
|
||||||
|
x_pid.append(img.pid)
|
||||||
|
if img.uid not in x_uid:
|
||||||
|
x_uid.append(img.uid)
|
||||||
|
await Text(
|
||||||
|
"从未更新过的UID:"
|
||||||
|
+ ",".join([f"uid:{x}" for x in _uid if x not in x_uid])
|
||||||
|
+ "\n"
|
||||||
|
+ "从未更新过的PID:"
|
||||||
|
+ ",".join([f"pid:{x}" for x in _pid if x not in x_pid])
|
||||||
|
).send()
|
||||||
|
if arparma.find("update"):
|
||||||
|
await Text("开始自动自动更新PID....").send()
|
||||||
|
update_lst = [f"pid:{x}" for x in _uid if x not in x_uid]
|
||||||
|
black_pid = await PixivKeywordUser.get_black_pid()
|
||||||
|
start_time = time.time()
|
||||||
|
pid_count, pic_count = await start_update_image_url(update_lst, black_pid, False)
|
||||||
|
await Text(
|
||||||
|
f"Pixiv搜图关键词搜图更新完成...\n"
|
||||||
|
f"累计更新PID {pid_count} 个\n"
|
||||||
|
f"累计更新图片 {pic_count} 张"
|
||||||
|
+ "\n耗时:{:.2f}秒".format((time.time() - start_time))
|
||||||
|
).send()
|
||||||
|
logger.info(
|
||||||
|
f"pix检测更新, 是否更新: {arparma.find('update')}",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_omega_matcher.handle()
|
||||||
|
async def _():
|
||||||
|
async def _tasks(line: str, all_pid: list[int], length: int, index: int):
|
||||||
|
data = line.split("VALUES", maxsplit=1)[-1].strip()[1:-2]
|
||||||
|
num_list = re.findall(r"(\d+)", data)
|
||||||
|
pid = int(num_list[1])
|
||||||
|
uid = int(num_list[2])
|
||||||
|
id_ = 3
|
||||||
|
while num_list[id_] not in ["0", "1"]:
|
||||||
|
id_ += 1
|
||||||
|
classified = int(num_list[id_])
|
||||||
|
nsfw_tag = int(num_list[id_ + 1])
|
||||||
|
width = int(num_list[id_ + 2])
|
||||||
|
height = int(num_list[id_ + 3])
|
||||||
|
str_list = re.findall(r"'(.*?)',", data)
|
||||||
|
title = str_list[0]
|
||||||
|
uname = str_list[1]
|
||||||
|
tags = str_list[2]
|
||||||
|
url = str_list[3]
|
||||||
|
if pid in all_pid:
|
||||||
|
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
|
||||||
|
return
|
||||||
|
_, is_create = await OmegaPixivIllusts.get_or_create(
|
||||||
|
pid=pid,
|
||||||
|
title=title,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
url=url,
|
||||||
|
uid=uid,
|
||||||
|
nsfw_tag=nsfw_tag,
|
||||||
|
tags=tags,
|
||||||
|
uname=uname,
|
||||||
|
classified=classified,
|
||||||
|
)
|
||||||
|
if is_create:
|
||||||
|
logger.info(
|
||||||
|
f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
|
||||||
|
|
||||||
|
omega_pixiv_illusts = None
|
||||||
|
for file in os.listdir("."):
|
||||||
|
if "omega_pixiv_artwork" in file and ".sql" in file:
|
||||||
|
omega_pixiv_illusts = Path() / file
|
||||||
|
if omega_pixiv_illusts:
|
||||||
|
with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
tasks = []
|
||||||
|
length = len([x for x in lines if "INSERT INTO" in x.upper()])
|
||||||
|
all_pid = await OmegaPixivIllusts.all().values_list("pid", flat=True)
|
||||||
|
index = 0
|
||||||
|
logger.info("检测到OmegaPixivIllusts数据库,准备开始更新....")
|
||||||
|
for line in lines:
|
||||||
|
if "INSERT INTO" in line.upper():
|
||||||
|
index += 1
|
||||||
|
logger.info(f"line: {line} 加入更新计划")
|
||||||
|
tasks.append(
|
||||||
|
asyncio.create_task(_tasks(line, all_pid, length, index)) # type: ignore
|
||||||
|
)
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
omega_pixiv_illusts.unlink()
|
||||||
@ -36,3 +36,11 @@ class InsufficientGold(Exception):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NotFindSuperuser(Exception):
|
||||||
|
"""
|
||||||
|
未找到超级用户
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import random
|
||||||
from typing import Awaitable, Callable, Literal, Set
|
from typing import Awaitable, Callable, Literal, Set
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@ -20,11 +21,13 @@ from nonebot_plugin_saa import (
|
|||||||
TargetQQPrivate,
|
TargetQQPrivate,
|
||||||
Text,
|
Text,
|
||||||
)
|
)
|
||||||
|
from nonebot_plugin_saa.abstract_factories import Receipt
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from zhenxun.models.friend_user import FriendUser
|
from zhenxun.models.friend_user import FriendUser
|
||||||
from zhenxun.models.group_console import GroupConsole
|
from zhenxun.models.group_console import GroupConsole
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.exception import NotFindSuperuser
|
||||||
|
|
||||||
|
|
||||||
class UserData(BaseModel):
|
class UserData(BaseModel):
|
||||||
@ -47,6 +50,34 @@ class UserData(BaseModel):
|
|||||||
|
|
||||||
class PlatformUtils:
|
class PlatformUtils:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def send_superuser(
|
||||||
|
cls,
|
||||||
|
bot: Bot,
|
||||||
|
message: str | MessageFactory | Text | Image,
|
||||||
|
superuser_id: str | None = None,
|
||||||
|
) -> Receipt | None:
|
||||||
|
"""发送消息给超级用户
|
||||||
|
|
||||||
|
参数:
|
||||||
|
bot: Bot
|
||||||
|
message: 消息
|
||||||
|
superuser_id: 指定超级用户id.
|
||||||
|
|
||||||
|
异常:
|
||||||
|
NotFindSuperuser: 未找到超级用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Receipt | None: Receipt
|
||||||
|
"""
|
||||||
|
if not superuser_id:
|
||||||
|
platform = cls.get_platform(bot)
|
||||||
|
platform_superusers = bot.config.PLATFORM_SUPERUSERS.get(platform) or []
|
||||||
|
if not platform_superusers:
|
||||||
|
raise NotFindSuperuser()
|
||||||
|
superuser_id = random.choice(platform_superusers)
|
||||||
|
return await cls.send_message(bot, superuser_id, None, message)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_group_member_list(cls, bot: Bot, group_id: str) -> list[UserData]:
|
async def get_group_member_list(cls, bot: Bot, group_id: str) -> list[UserData]:
|
||||||
"""获取群组/频道成员列表
|
"""获取群组/频道成员列表
|
||||||
@ -277,7 +308,7 @@ class PlatformUtils:
|
|||||||
user_id: str | None,
|
user_id: str | None,
|
||||||
group_id: str | None,
|
group_id: str | None,
|
||||||
message: str | Text | MessageFactory | Image,
|
message: str | Text | MessageFactory | Image,
|
||||||
) -> bool:
|
) -> Receipt | None:
|
||||||
"""发送消息
|
"""发送消息
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
@ -287,13 +318,12 @@ class PlatformUtils:
|
|||||||
message: 消息文本
|
message: 消息文本
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否发送成功
|
Receipt | None: 是否发送成功
|
||||||
"""
|
"""
|
||||||
if target := cls.get_target(bot, user_id, group_id):
|
if target := cls.get_target(bot, user_id, group_id):
|
||||||
send_message = Text(message) if isinstance(message, str) else message
|
send_message = Text(message) if isinstance(message, str) else message
|
||||||
await send_message.send_to(target, bot)
|
return await send_message.send_to(target, bot)
|
||||||
return True
|
return None
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_group(cls, bot: Bot) -> int:
|
async def update_group(cls, bot: Bot) -> int:
|
||||||
@ -581,7 +611,10 @@ async def broadcast_group(
|
|||||||
if is_continue:
|
if is_continue:
|
||||||
continue
|
continue
|
||||||
target = PlatformUtils.get_target(
|
target = PlatformUtils.get_target(
|
||||||
_bot, None, group.group_id, group.channel_id
|
_bot,
|
||||||
|
None,
|
||||||
|
group.group_id,
|
||||||
|
# , group.channel_id
|
||||||
)
|
)
|
||||||
if target:
|
if target:
|
||||||
_used_group.append(key)
|
_used_group.append(key)
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import httpx
|
|||||||
import pypinyin
|
import pypinyin
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
|
|
||||||
@ -165,3 +166,50 @@ async def get_group_avatar(gid: int | str) -> bytes | None:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("获取群头像错误", "Util", target=gid)
|
logger.error("获取群头像错误", "Util", target=gid)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def change_pixiv_image_links(
|
||||||
|
url: str, size: str | None = None, nginx_url: str | None = None
|
||||||
|
) -> str:
|
||||||
|
"""根据配置改变图片大小和反代链接
|
||||||
|
|
||||||
|
参数:
|
||||||
|
url: 图片原图链接
|
||||||
|
size: 模式
|
||||||
|
nginx_url: 反代
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str: url
|
||||||
|
"""
|
||||||
|
if size == "master":
|
||||||
|
img_sp = url.rsplit(".", maxsplit=1)
|
||||||
|
url = img_sp[0]
|
||||||
|
img_type = img_sp[1]
|
||||||
|
url = url.replace("original", "master") + f"_master1200.{img_type}"
|
||||||
|
if not nginx_url:
|
||||||
|
nginx_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
||||||
|
if nginx_url:
|
||||||
|
url = (
|
||||||
|
url.replace("i.pximg.net", nginx_url)
|
||||||
|
.replace("i.pixiv.cat", nginx_url)
|
||||||
|
.replace("_webp", "")
|
||||||
|
)
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
def change_img_md5(path_file: str | Path) -> bool:
|
||||||
|
"""改变图片MD5
|
||||||
|
|
||||||
|
参数:
|
||||||
|
path_file: 图片路径
|
||||||
|
|
||||||
|
返还:
|
||||||
|
bool: 是否修改成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(path_file, "a") as f:
|
||||||
|
f.write(str(int(time.time() * 1000)))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"改变图片MD5错误 Path:{path_file}", e=e)
|
||||||
|
return False
|
||||||
|
|||||||
@ -64,7 +64,11 @@ class WithdrawManager:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def withdraw_message(
|
async def withdraw_message(
|
||||||
cls, bot: Bot, message_id: str | int, time: int | None = None
|
cls,
|
||||||
|
bot: Bot,
|
||||||
|
message_id: str | int,
|
||||||
|
time: int | tuple[int, int] | None = None,
|
||||||
|
session: EventSession | None = None,
|
||||||
):
|
):
|
||||||
"""消息撤回
|
"""消息撤回
|
||||||
|
|
||||||
@ -74,8 +78,24 @@ class WithdrawManager:
|
|||||||
time: 延迟时间
|
time: 延迟时间
|
||||||
"""
|
"""
|
||||||
if time:
|
if time:
|
||||||
logger.debug(f"将在 {time}秒 内撤回消息ID: {message_id}", "WithdrawManager")
|
gid = None
|
||||||
await asyncio.sleep(time)
|
_time = 1
|
||||||
|
if isinstance(time, tuple):
|
||||||
|
if time[0] == 0:
|
||||||
|
return
|
||||||
|
if session:
|
||||||
|
gid = session.id3 or session.id2
|
||||||
|
if not gid and int(time[1]) not in [0, 2]:
|
||||||
|
return
|
||||||
|
if gid and int(time[1]) not in [1, 2]:
|
||||||
|
return
|
||||||
|
_time = time[0]
|
||||||
|
else:
|
||||||
|
_time = time
|
||||||
|
logger.debug(
|
||||||
|
f"将在 {_time}秒 内撤回消息ID: {message_id}", "WithdrawManager"
|
||||||
|
)
|
||||||
|
await asyncio.sleep(_time)
|
||||||
if isinstance(bot, v11Bot):
|
if isinstance(bot, v11Bot):
|
||||||
logger.debug(f"v11Bot 撤回消息ID: {message_id}", "WithdrawManager")
|
logger.debug(f"v11Bot 撤回消息ID: {message_id}", "WithdrawManager")
|
||||||
await bot.delete_msg(message_id=int(message_id))
|
await bot.delete_msg(message_id=int(message_id))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user